From: Ruiyu Ni <ruiyu.ni@intel.com>
To: edk2-devel@lists.01.org
Cc: Andrew Fish <afish@intel.com>, Hao A Wu <hao.a.wu@intel.com>
Subject: [PATCH 05/12] EmulatorPkg/Win: Add input/output support
Date: Thu, 23 Aug 2018 17:52:08 +0800 [thread overview]
Message-ID: <20180823095215.274248-6-ruiyu.ni@intel.com> (raw)
In-Reply-To: <20180823095215.274248-1-ruiyu.ni@intel.com>
The patch adds GOP and SimpleTextIn[Ex] support.
Now firmware can boot to UI and Shell but timer doesn't work.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Andrew Fish <afish@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
---
EmulatorPkg/Win/Host/WinGop.h | 204 +++++++++
EmulatorPkg/Win/Host/WinGopInput.c | 417 +++++++++++++++++
EmulatorPkg/Win/Host/WinGopScreen.c | 872 ++++++++++++++++++++++++++++++++++++
EmulatorPkg/Win/Host/WinHost.c | 5 +
EmulatorPkg/Win/Host/WinHost.h | 1 +
EmulatorPkg/Win/Host/WinHost.inf | 7 +
6 files changed, 1506 insertions(+)
create mode 100644 EmulatorPkg/Win/Host/WinGop.h
create mode 100644 EmulatorPkg/Win/Host/WinGopInput.c
create mode 100644 EmulatorPkg/Win/Host/WinGopScreen.c
diff --git a/EmulatorPkg/Win/Host/WinGop.h b/EmulatorPkg/Win/Host/WinGop.h
new file mode 100644
index 0000000000..32ae6b03af
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGop.h
@@ -0,0 +1,204 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+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.
+
+Module Name:
+
+ WinGop.h
+
+Abstract:
+
+ Private data for the Gop driver that is bound to the WinNt Thunk protocol
+
+
+**/
+
+#ifndef _WIN_GOP_H_
+#define _WIN_GOP_H_
+
+
+#include "WinHost.h"
+
+#include <Protocol/EmuIoThunk.h>
+#include <Protocol/EmuGraphicsWindow.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/GraphicsOutput.h>
+
+//
+// WM_SYSKEYDOWN/WM_SYSKEYUP Notification
+// lParam
+// bit 24: Specifies whether the key is an extended key,
+// such as the right-hand ALT and CTRL keys that appear on
+// an enhanced 101- or 102-key keyboard.
+// The value is 1 if it is an extended key; otherwise, it is 0.
+// bit 29:Specifies the context code.
+// The value is 1 if the ALT key is down while the key is pressed/released;
+// it is 0 if the WM_SYSKEYDOWN message is posted to the active window
+// because no window has the keyboard focus.
+#define GOP_EXTENDED_KEY (0x1 << 24)
+#define GOP_ALT_KEY_PRESSED (0x1 << 29)
+
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+
+#define MAX_Q 256
+
+typedef struct {
+ UINTN Front;
+ UINTN Rear;
+ EFI_KEY_DATA Q[MAX_Q];
+ CRITICAL_SECTION Cs;
+} GOP_QUEUE_FIXED;
+
+#define WIN_NT_GOP_CLASS_NAME L"WinNtGopWindow"
+
+
+typedef struct {
+ UINT64 Signature;
+ EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsWindowIo;
+
+ //
+ // GOP Private Data knowing when to start hardware
+ //
+ BOOLEAN HardwareNeedsStarting;
+
+ CHAR16 *WindowName;
+ CHAR16 Buffer[160];
+
+ HANDLE ThreadInited; // Semaphore
+ HANDLE ThreadHandle; // Thread
+ DWORD ThreadId;
+
+ HWND WindowHandle;
+ WNDCLASSEX WindowsClass;
+
+ UINT32 Width;
+ UINT32 Height;
+ //
+ // This screen is used to redraw the scree when windows events happen. It's
+ // updated in the main thread and displayed in the windows thread.
+ //
+ BITMAPV4HEADER *VirtualScreenInfo;
+ RGBQUAD *VirtualScreen;
+
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillLine;
+
+ //
+ // Keyboard Queue used by Simple Text In.
+ // QueueForRead: WinProc thread adds, and main thread removes.
+ //
+ GOP_QUEUE_FIXED QueueForRead;
+
+ EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback;
+ EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback;
+ VOID *RegisterdKeyCallbackContext;
+
+ EFI_KEY_STATE KeyState;
+ BOOLEAN LeftShift;
+ BOOLEAN RightShift;
+ BOOLEAN LeftAlt;
+ BOOLEAN RightAlt;
+ BOOLEAN LeftCtrl;
+ BOOLEAN RightCtrl;
+ BOOLEAN LeftLogo;
+ BOOLEAN RightLogo;
+ BOOLEAN Menu;
+ BOOLEAN SysReq;
+ BOOLEAN NumLock;
+ BOOLEAN ScrollLock;
+ BOOLEAN CapsLock;
+ BOOLEAN IsPartialKeySupport;
+} GRAPHICS_PRIVATE_DATA;
+#define GRAPHICS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('g', 'f', 'x', 'd')
+#define GRAPHICS_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, GRAPHICS_PRIVATE_DATA, GraphicsWindowIo, GRAPHICS_PRIVATE_DATA_SIGNATURE)
+
+
+//
+// Gop Hardware abstraction internal worker functions
+//
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @return TODO: add return values
+
+**/
+EFI_STATUS
+GopPrivateAddKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_INPUT_KEY Key
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_DATA *KeyData
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndKeySetState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndRegisterKeyNotify (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckPointer (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ );
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetPointerState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_SIMPLE_POINTER_STATE *State
+ );
+EFI_STATUS
+GopPrivateCreateQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ );
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDestroyQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ );
+#endif
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinGopInput.c b/EmulatorPkg/Win/Host/WinGopInput.c
new file mode 100644
index 0000000000..7223f6a185
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGopInput.c
@@ -0,0 +1,417 @@
+/** @file
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+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.
+
+Module Name:
+
+ WinGopInput.c
+
+Abstract:
+
+ This file produces the Simple Text In for an Gop window.
+
+ This stuff is linked at the hip to the Window, since the window
+ processing is done in a thread kicked off in WinNtGopImplementation.c
+
+ Since the window information is processed in an other thread we need
+ a keyboard Queue to pass data about. The Simple Text In code just
+ takes data off the Queue. The WinProc message loop takes keyboard input
+ and places it in the Queue.
+
+
+**/
+
+
+#include "WinGop.h"
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateCreateQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ InitializeCriticalSection (&Queue->Cs);
+ Queue->Front = 0;
+ Queue->Rear = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDestroyQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ Queue->Front = 0;
+ Queue->Rear = 0;
+ DeleteCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateAddQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ EnterCriticalSection (&Queue->Cs);
+
+ if ((Queue->Rear + 1) % MAX_Q == Queue->Front) {
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (&Queue->Q[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Rear = (Queue->Rear + 1) % MAX_Q;
+
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateDeleteQ (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN GOP_QUEUE_FIXED *Queue,
+ OUT EFI_KEY_DATA *Key
+ )
+{
+ EnterCriticalSection (&Queue->Cs);
+
+ if (Queue->Front == Queue->Rear) {
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (Key, &Queue->Q[Queue->Front], sizeof (EFI_KEY_DATA));
+ Queue->Front = (Queue->Front + 1) % MAX_Q;
+
+ if (Key->Key.ScanCode == SCAN_NULL && Key->Key.UnicodeChar == CHAR_NULL) {
+ if (!Private->IsPartialKeySupport) {
+ //
+ // If partial keystrok is not enabled, don't return the partial keystroke.
+ //
+ LeaveCriticalSection (&Queue->Cs);
+ ZeroMem (Key, sizeof (EFI_KEY_DATA));
+ return EFI_NOT_READY;
+ }
+ }
+ LeaveCriticalSection (&Queue->Cs);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateCheckQ (
+ IN GOP_QUEUE_FIXED *Queue
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the key state.
+
+ @param Private The GOP_PRIVATE_DATA instance.
+ @param KeyState A pointer to receive the key state information.
+**/
+VOID
+InitializeKeyState (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_KEY_STATE *KeyState
+ )
+{
+ KeyState->KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyState->KeyToggleState = EFI_TOGGLE_STATE_VALID;
+
+ //
+ // Record Key shift state and toggle state
+ //
+ if (Private->LeftCtrl) {
+ KeyState->KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
+ }
+ if (Private->RightCtrl) {
+ KeyState->KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if (Private->LeftAlt) {
+ KeyState->KeyShiftState |= EFI_LEFT_ALT_PRESSED;
+ }
+ if (Private->RightAlt) {
+ KeyState->KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
+ }
+ if (Private->LeftShift) {
+ KeyState->KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+ if (Private->RightShift) {
+ KeyState->KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+ if (Private->LeftLogo) {
+ KeyState->KeyShiftState |= EFI_LEFT_LOGO_PRESSED;
+ }
+ if (Private->RightLogo) {
+ KeyState->KeyShiftState |= EFI_RIGHT_LOGO_PRESSED;
+ }
+ if (Private->Menu) {
+ KeyState->KeyShiftState |= EFI_MENU_KEY_PRESSED;
+ }
+ if (Private->SysReq) {
+ KeyState->KeyShiftState |= EFI_SYS_REQ_PRESSED;
+ }
+ if (Private->CapsLock) {
+ KeyState->KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
+ }
+ if (Private->NumLock) {
+ KeyState->KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
+ }
+ if (Private->ScrollLock) {
+ KeyState->KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
+ }
+ if (Private->IsPartialKeySupport) {
+ KeyState->KeyToggleState |= EFI_KEY_STATE_EXPOSED;
+ }
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Key TODO: add argument description
+
+ @retval EFI_NOT_READY TODO: Add description for return value
+ @retval EFI_SUCCESS TODO: Add description for return value
+
+**/
+EFI_STATUS
+GopPrivateAddKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN EFI_INPUT_KEY Key
+ )
+{
+ EFI_KEY_DATA KeyData;
+
+ KeyData.Key = Key;
+ InitializeKeyState (Private, &KeyData.KeyState);
+
+ //
+ // Convert Ctrl+[1-26] to Ctrl+[A-Z]
+ //
+ if ((Private->LeftCtrl || Private->RightCtrl) &&
+ (KeyData.Key.UnicodeChar >= 1) && (KeyData.Key.UnicodeChar <= 26)
+ ) {
+ if ((Private->LeftShift || Private->RightShift) == Private->CapsLock) {
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'a' - 1);
+ } else {
+ KeyData.Key.UnicodeChar = (CHAR16)(KeyData.Key.UnicodeChar + L'A' - 1);
+ }
+ }
+
+ //
+ // Unmask the Shift bit for printable char
+ //
+ if (((KeyData.Key.UnicodeChar >= L'a') && (KeyData.Key.UnicodeChar <= L'z')) ||
+ ((KeyData.Key.UnicodeChar >= L'A') && (KeyData.Key.UnicodeChar <= L'Z'))
+ ) {
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
+ }
+
+ GopPrivateAddQ (Private, &Private->QueueForRead, &KeyData);
+ if (Private->MakeRegisterdKeyCallback != NULL) {
+ Private->MakeRegisterdKeyCallback (Private->RegisterdKeyCallbackContext, &KeyData);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ return GopPrivateCheckQ (&Private->QueueForRead);
+
+}
+EFI_STATUS
+EFIAPI
+WinNtWndGetKey (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_DATA *KeyData
+ )
+/*++
+
+ Routine Description:
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ Arguments:
+ Private - The private structure of WinNt Gop device.
+ KeyData - A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ Returns:
+ EFI_SUCCESS - The keystroke information was returned.
+ EFI_NOT_READY - There was no keystroke data availiable.
+ EFI_DEVICE_ERROR - The keystroke information was not returned due to
+ hardware errors.
+ EFI_INVALID_PARAMETER - KeyData is NULL.
+
+--*/
+{
+ EFI_STATUS Status;
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ ZeroMem (&KeyData->Key, sizeof (KeyData->Key));
+ InitializeKeyState (Private, &KeyData->KeyState);
+
+ Status = GopPrivateCheckQ (&Private->QueueForRead);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If a Key press exists try and read it.
+ //
+ Status = GopPrivateDeleteQ (Private, &Private->QueueForRead, KeyData);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If partial keystroke is not enabled, check whether it is value key. If not return
+ // EFI_NOT_READY.
+ //
+ if (!Private->IsPartialKeySupport) {
+ if (KeyData->Key.ScanCode == SCAN_NULL && KeyData->Key.UnicodeChar == CHAR_NULL) {
+ Status = EFI_NOT_READY;
+ }
+ }
+ }
+ }
+
+ return Status;
+
+}
+
+EFI_STATUS
+EFIAPI
+WinNtWndKeySetState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+ Private->KeyState.KeyToggleState = *KeyToggleState;
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtWndRegisterKeyNotify (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
+ IN VOID *Context
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ Private->MakeRegisterdKeyCallback = MakeCallBack;
+ Private->BreakRegisterdKeyCallback = BreakCallBack;
+ Private->RegisterdKeyCallbackContext = Context;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+WinNtWndCheckPointer (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ return EFI_NOT_READY;
+}
+
+
+EFI_STATUS
+EFIAPI
+WinNtWndGetPointerState (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ return EFI_NOT_READY;
+}
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinGopScreen.c b/EmulatorPkg/Win/Host/WinGopScreen.c
new file mode 100644
index 0000000000..2ca51d23d0
--- /dev/null
+++ b/EmulatorPkg/Win/Host/WinGopScreen.c
@@ -0,0 +1,872 @@
+/** @file
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+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.
+
+Module Name:
+
+ WinGopScreen.c
+
+Abstract:
+
+ This file produces the graphics abstration of GOP. It is called by
+ WinNtGopDriver.c file which deals with the UEFI 2.0 driver model.
+ This file just does graphics.
+
+
+**/
+
+#include "WinGop.h"
+
+DWORD mTlsIndex = TLS_OUT_OF_INDEXES;
+DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex.
+
+BOOLEAN
+WinNtGopConvertParamToEfiKeyShiftState (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN WPARAM *wParam,
+ IN LPARAM *lParam,
+ IN BOOLEAN Flag
+ )
+{
+ switch (*wParam) {
+ //
+ // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish
+ // left and right Ctrl, and Shift key.
+ // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL.
+ // Therefor, we can not set the correct Shift state here.
+ //
+ case VK_SHIFT:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightShift = Flag;
+ } else {
+ Private->LeftShift = Flag;
+ }
+ return TRUE;
+
+ case VK_LSHIFT:
+ Private->LeftShift = Flag;
+ return TRUE;
+
+ case VK_RSHIFT:
+ Private->RightShift = Flag;
+ return TRUE;
+
+ case VK_CONTROL:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightCtrl= Flag;
+ } else {
+ Private->LeftCtrl = Flag;
+ }
+ return TRUE;
+
+ case VK_LCONTROL:
+ Private->LeftCtrl = Flag;
+ return TRUE;
+
+ case VK_RCONTROL:
+ Private->RightCtrl = Flag;
+ return TRUE;
+
+ case VK_LWIN:
+ Private->LeftLogo = Flag;
+ return TRUE;
+
+ case VK_RWIN:
+ Private->RightLogo = Flag;
+ return TRUE;
+
+ case VK_APPS:
+ Private->Menu = Flag;
+ return TRUE;
+ //
+ // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message,
+ // so SySReq shift state is not supported here.
+ //
+ case VK_PRINT:
+ Private->SysReq = Flag;
+ return TRUE;
+ //
+ // For Alt Keystroke.
+ //
+ case VK_MENU:
+ if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
+ Private->RightAlt = Flag;
+ } else {
+ Private->LeftAlt = Flag;
+ }
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+BOOLEAN
+WinNtGopConvertParamToEfiKey (
+ IN GRAPHICS_PRIVATE_DATA *Private,
+ IN WPARAM *wParam,
+ IN LPARAM *lParam,
+ IN EFI_INPUT_KEY *Key
+ )
+{
+ BOOLEAN Flag;
+ Flag = FALSE;
+ switch (*wParam) {
+ case VK_HOME: Key->ScanCode = SCAN_HOME; Flag = TRUE; break;
+ case VK_END: Key->ScanCode = SCAN_END; Flag = TRUE; break;
+ case VK_LEFT: Key->ScanCode = SCAN_LEFT; Flag = TRUE; break;
+ case VK_RIGHT: Key->ScanCode = SCAN_RIGHT; Flag = TRUE; break;
+ case VK_UP: Key->ScanCode = SCAN_UP; Flag = TRUE; break;
+ case VK_DOWN: Key->ScanCode = SCAN_DOWN; Flag = TRUE; break;
+ case VK_DELETE: Key->ScanCode = SCAN_DELETE; Flag = TRUE; break;
+ case VK_INSERT: Key->ScanCode = SCAN_INSERT; Flag = TRUE; break;
+ case VK_PRIOR: Key->ScanCode = SCAN_PAGE_UP; Flag = TRUE; break;
+ case VK_NEXT: Key->ScanCode = SCAN_PAGE_DOWN; Flag = TRUE; break;
+ case VK_ESCAPE: Key->ScanCode = SCAN_ESC; Flag = TRUE; break;
+
+ case VK_F1: Key->ScanCode = SCAN_F1; Flag = TRUE; break;
+ case VK_F2: Key->ScanCode = SCAN_F2; Flag = TRUE; break;
+ case VK_F3: Key->ScanCode = SCAN_F3; Flag = TRUE; break;
+ case VK_F4: Key->ScanCode = SCAN_F4; Flag = TRUE; break;
+ case VK_F5: Key->ScanCode = SCAN_F5; Flag = TRUE; break;
+ case VK_F6: Key->ScanCode = SCAN_F6; Flag = TRUE; break;
+ case VK_F7: Key->ScanCode = SCAN_F7; Flag = TRUE; break;
+ case VK_F8: Key->ScanCode = SCAN_F8; Flag = TRUE; break;
+ case VK_F9: Key->ScanCode = SCAN_F9; Flag = TRUE; break;
+ case VK_F11: Key->ScanCode = SCAN_F11; Flag = TRUE; break;
+ case VK_F12: Key->ScanCode = SCAN_F12; Flag = TRUE; break;
+
+ case VK_F13: Key->ScanCode = SCAN_F13; Flag = TRUE; break;
+ case VK_F14: Key->ScanCode = SCAN_F14; Flag = TRUE; break;
+ case VK_F15: Key->ScanCode = SCAN_F15; Flag = TRUE; break;
+ case VK_F16: Key->ScanCode = SCAN_F16; Flag = TRUE; break;
+ case VK_F17: Key->ScanCode = SCAN_F17; Flag = TRUE; break;
+ case VK_F18: Key->ScanCode = SCAN_F18; Flag = TRUE; break;
+ case VK_F19: Key->ScanCode = SCAN_F19; Flag = TRUE; break;
+ case VK_F20: Key->ScanCode = SCAN_F20; Flag = TRUE; break;
+ case VK_F21: Key->ScanCode = SCAN_F21; Flag = TRUE; break;
+ case VK_F22: Key->ScanCode = SCAN_F22; Flag = TRUE; break;
+ case VK_F23: Key->ScanCode = SCAN_F23; Flag = TRUE; break;
+ case VK_F24: Key->ScanCode = SCAN_F24; Flag = TRUE; break;
+ case VK_PAUSE: Key->ScanCode = SCAN_PAUSE; Flag = TRUE; break;
+
+ //
+ // Set toggle state
+ //
+ case VK_NUMLOCK:
+ Private->NumLock = (BOOLEAN)(!Private->NumLock);
+ Flag = TRUE;
+ break;
+ case VK_SCROLL:
+ Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);
+ Flag = TRUE;
+ break;
+ case VK_CAPITAL:
+ Private->CapsLock = (BOOLEAN)(!Private->CapsLock);
+ Flag = TRUE;
+ break;
+ }
+
+ return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag;
+}
+
+
+//
+// GOP Protocol Member Functions
+//
+
+/**
+ Change the resolution and resize of the window
+**/
+EFI_STATUS
+EFIAPI
+WinNtWndSize (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN UINT32 Width,
+ IN UINT32 Height
+)
+{
+ UINT32 Size;
+ GRAPHICS_PRIVATE_DATA *Private;
+ RECT Rect;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewFillLine;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+ Private->Width = Width;
+ Private->Height = Height;
+
+
+ //
+ // Free the old buffer. We do not save the content of the old buffer since the
+ // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
+ // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()
+ //
+ if (Private->VirtualScreenInfo != NULL) {
+ HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
+ }
+
+ //
+ // Allocate DIB frame buffer directly from NT for performance enhancement
+ // This buffer is the virtual screen/frame buffer. This buffer is not the
+ // same a a frame buffer. The first row of this buffer will be the bottom
+ // line of the image. This is an artifact of the way we draw to the screen.
+ //
+ Size = Private->Width * Private->Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);
+ Private->VirtualScreenInfo = HeapAlloc (
+ GetProcessHeap (),
+ HEAP_ZERO_MEMORY,
+ Size
+ );
+
+ //
+ // Update the virtual screen info data structure
+ //
+ Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
+ Private->VirtualScreenInfo->bV4Width = Private->Width;
+ Private->VirtualScreenInfo->bV4Height = Private->Height;
+ Private->VirtualScreenInfo->bV4Planes = 1;
+ Private->VirtualScreenInfo->bV4BitCount = 32;
+ //
+ // uncompressed
+ //
+ Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
+
+ //
+ // The rest of the allocated memory block is the virtual screen buffer
+ //
+ Private->VirtualScreen = (RGBQUAD *)(Private->VirtualScreenInfo + 1);
+
+ //
+ // Use the AdjuctWindowRect fuction to calculate the real width and height
+ // of the new window including the border and caption
+ //
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = Private->Width;
+ Rect.bottom = Private->Height;
+
+ AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
+
+ Width = Rect.right - Rect.left;
+ Height = Rect.bottom - Rect.top;
+
+ //
+ // Retrieve the original window position information
+ //
+ GetWindowRect (Private->WindowHandle, &Rect);
+
+ //
+ // Adjust the window size
+ //
+ MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);
+
+ NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Private->Width);
+ if (NewFillLine == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Private->FillLine != NULL) {
+ FreePool (Private->FillLine);
+ }
+
+ Private->FillLine = NewFillLine;
+ return EFI_SUCCESS;
+}
+
+/**
+ Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
+ onto the graphics screen starting a location (X, Y). (0, 0) is defined as
+ the upper left hand side of the screen. (X, Y) can be outside of the
+ current screen geometry and the BltBuffer will be cliped when it is
+ displayed. X and Y can be negative or positive. If Width or Height is
+ bigger than the current video screen the image will be clipped.
+
+ @param This Protocol instance pointer.
+ @param X X location on graphics screen.
+ @param Y Y location on the graphics screen.
+ @param Width Width of BltBuffer.
+ @param Height Hight of BltBuffer
+ @param BltOperation Operation to perform on BltBuffer and video memory
+ @param BltBuffer Buffer containing data to blt into video buffer.
+ This buffer has a size of
+ Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ @param SourceX If the BltOperation is a EfiCopyBlt this is the
+ source of the copy. For other BLT operations this
+ argument is not used.
+ @param SourceX If the BltOperation is a EfiCopyBlt this is the
+ source of the copy. For other BLT operations this
+ argument is not used.
+
+ @retval EFI_SUCCESS The palette is updated with PaletteArray.
+ @retval EFI_INVALID_PARAMETER BltOperation is not valid.
+ @retval EFI_DEVICE_ERROR A hardware error occured writting to the video
+ buffer.
+
+**/
+// TODO: SourceY - add argument and description to function comment
+// TODO: DestinationX - add argument and description to function comment
+// TODO: DestinationY - add argument and description to function comment
+// TODO: Delta - add argument and description to function comment
+EFI_STATUS
+WinNtWndBlt (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo,
+ IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
+)
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+ UINTN DstY;
+ UINTN SrcY;
+ RGBQUAD *VScreen;
+ RGBQUAD *VScreenSrc;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINTN Index;
+ RECT Rect;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;
+ UINT32 VerticalResolution;
+ UINT32 HorizontalResolution;
+
+ Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);
+
+ //
+ // We need to fill the Virtual Screen buffer with the blt data.
+ // The virtual screen is upside down, as the first row is the bootom row of
+ // the image.
+ //
+ VerticalResolution = Private->VirtualScreenInfo->bV4Height;
+ HorizontalResolution = Private->VirtualScreenInfo->bV4Width;
+ if (BltOperation == EfiBltVideoToBltBuffer) {
+
+ for (SrcY = Args->SourceY, DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); SrcY++, DstY++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Args->Delta) + Args->DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];
+ CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Args->Width);
+ }
+ } else {
+ if (BltOperation == EfiBltVideoFill) {
+ FillPixel = BltBuffer;
+ for (Index = 0; Index < Args->Width; Index++) {
+ Private->FillLine[Index] = *FillPixel;
+ }
+ }
+
+ for (Index = 0; Index < Args->Height; Index++) {
+ if (Args->DestinationY <= Args->SourceY) {
+ SrcY = Args->SourceY + Index;
+ DstY = Args->DestinationY + Index;
+ } else {
+ SrcY = Args->SourceY + Args->Height - Index - 1;
+ DstY = Args->DestinationY + Args->Height - Index - 1;
+ }
+
+ VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + Args->DestinationX];
+ switch (BltOperation) {
+ case EfiBltBufferToVideo:
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Args->Delta) + Args->SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ CopyMem (VScreen, Blt, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ break;
+
+ case EfiBltVideoToVideo:
+ VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];
+ CopyMem (VScreen, VScreenSrc, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ break;
+
+ case EfiBltVideoFill:
+ CopyMem (VScreen, Private->FillLine, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ break;
+ }
+ }
+ }
+
+ if (BltOperation != EfiBltVideoToBltBuffer) {
+ //
+ // Mark the area we just blted as Invalid so WM_PAINT will update.
+ //
+ Rect.left = (LONG)Args->DestinationX;
+ Rect.top = (LONG)Args->DestinationY;
+ Rect.right = (LONG)(Args->DestinationX + Args->Width);
+ Rect.bottom = (LONG)(Args->DestinationY + Args->Height);
+ InvalidateRect (Private->WindowHandle, &Rect, FALSE);
+
+ //
+ // Send the WM_PAINT message to the thread that is drawing the window. We
+ // are in the main thread and the window drawing is in a child thread.
+ // There is a child thread per window. We have no CriticalSection or Mutex
+ // since we write the data and the other thread displays the data. While
+ // we may miss some data for a short period of time this is no different than
+ // a write combining on writes to a frame buffer.
+ //
+
+ UpdateWindow (Private->WindowHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Win32 Windows event handler.
+
+ See Win32 Book
+
+ @return See Win32 Book
+
+**/
+// TODO: hwnd - add argument and description to function comment
+// TODO: iMsg - add argument and description to function comment
+// TODO: wParam - add argument and description to function comment
+// TODO: lParam - add argument and description to function comment
+LRESULT
+CALLBACK
+WinNtGopThreadWindowProc (
+ IN HWND hwnd,
+ IN UINT iMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+ UINTN Size;
+ HDC Handle;
+ PAINTSTRUCT PaintStruct;
+ LPARAM Index;
+ EFI_INPUT_KEY Key;
+ BOOLEAN AltIsPress;
+
+ //
+ // BugBug - if there are two instances of this DLL in memory (such as is
+ // the case for ERM), the correct instance of this function may not be called.
+ // This also means that the address of the mTlsIndex value will be wrong, and
+ // the value may be wrong too.
+ //
+
+
+ //
+ // Use mTlsIndex global to get a Thread Local Storage version of Private.
+ // This works since each Gop protocol has a unique Private data instance and
+ // a unique thread.
+ //
+ AltIsPress = FALSE;
+ Private = TlsGetValue (mTlsIndex);
+ ASSERT (NULL != Private);
+
+ switch (iMsg) {
+ case WM_CREATE:
+ Size = Private->Width * Private->Height * sizeof (RGBQUAD);
+
+ //
+ // Allocate DIB frame buffer directly from NT for performance enhancement
+ // This buffer is the virtual screen/frame buffer. This buffer is not the
+ // same a a frame buffer. The first fow of this buffer will be the bottom
+ // line of the image. This is an artifact of the way we draw to the screen.
+ //
+ Private->VirtualScreenInfo = HeapAlloc (
+ GetProcessHeap (),
+ HEAP_ZERO_MEMORY,
+ Size
+ );
+
+ Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
+ Private->VirtualScreenInfo->bV4Width = Private->Width;
+ Private->VirtualScreenInfo->bV4Height = Private->Height;
+ Private->VirtualScreenInfo->bV4Planes = 1;
+ Private->VirtualScreenInfo->bV4BitCount = 32;
+ //
+ // uncompressed
+ //
+ Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
+ Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
+ return 0;
+
+ case WM_PAINT:
+ //
+ // I have not found a way to convert hwnd into a Private context. So for
+ // now we use this API to convert hwnd to Private data.
+ //
+
+ Handle = BeginPaint (hwnd, &PaintStruct);
+
+ SetDIBitsToDevice (
+ Handle, // Destination Device Context
+ 0, // Destination X - 0
+ 0, // Destination Y - 0
+ Private->Width, // Width
+ Private->Height, // Height
+ 0, // Source X
+ 0, // Source Y
+ 0, // DIB Start Scan Line
+ Private->Height, // Number of scan lines
+ Private->VirtualScreen, // Address of array of DIB bits
+ (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info
+ DIB_RGB_COLORS // RGB or palette indexes
+ );
+
+ EndPaint (hwnd, &PaintStruct);
+ return 0;
+
+ //
+ // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
+ // WM_SYSKEYDOWN is posted when F10 is pressed or
+ // holds down ALT key and then presses another key.
+ //
+ case WM_SYSKEYDOWN:
+
+ Key.ScanCode = 0;
+ Key.UnicodeChar = CHAR_NULL;
+ switch (wParam) {
+ case VK_F10:
+ Key.ScanCode = SCAN_F10;
+ Key.UnicodeChar = CHAR_NULL;
+ GopPrivateAddKey (Private, Key);
+ return 0;
+ }
+
+ //
+ // If ALT or ALT + modifier key is pressed.
+ //
+ if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
+ if (Key.ScanCode != 0){
+ //
+ // If ALT is pressed with other ScanCode.
+ // Always revers the left Alt for simple.
+ //
+ Private->LeftAlt = TRUE;
+ }
+ GopPrivateAddKey (Private, Key);
+ //
+ // When Alt is released there is no windoes message, so
+ // clean it after using it.
+ //
+ Private->RightAlt = FALSE;
+ Private->LeftAlt = FALSE;
+ return 0;
+ }
+ AltIsPress = TRUE;
+
+ case WM_CHAR:
+ //
+ // The ESC key also generate WM_CHAR.
+ //
+ if (wParam == 0x1B) {
+ return 0;
+ }
+
+ if (AltIsPress == TRUE) {
+ //
+ // If AltIsPress is true that means the Alt key is pressed.
+ //
+ Private->LeftAlt = TRUE;
+ }
+ for (Index = 0; Index < (lParam & 0xffff); Index++) {
+ if (wParam != 0) {
+ Key.UnicodeChar = (CHAR16) wParam;
+ Key.ScanCode = SCAN_NULL;
+ GopPrivateAddKey (Private, Key);
+ }
+ }
+ if (AltIsPress == TRUE) {
+ //
+ // When Alt is released there is no windoes message, so
+ // clean it after using it.
+ //
+ Private->LeftAlt = FALSE;
+ Private->RightAlt = FALSE;
+ }
+ return 0;
+
+ case WM_SYSKEYUP:
+ //
+ // ALT is pressed with another key released
+ //
+ WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
+ return 0;
+
+ case WM_KEYDOWN:
+ Key.ScanCode = SCAN_NULL;
+ Key.UnicodeChar = CHAR_NULL;
+ //
+ // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR
+ // So if there is no modifier key updated, skip the WM_KEYDOWN even.
+ //
+ if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
+ //
+ // Support the partial keystroke, add all keydown event into the queue.
+ //
+ GopPrivateAddKey (Private, Key);
+ }
+ return 0;
+
+ case WM_KEYUP:
+ WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
+ return 0;
+
+ case WM_CLOSE:
+ //
+ // This close message is issued by user, core is not aware of this,
+ // so don't release the window display resource, just hide the window.
+ //
+ ShowWindow (Private->WindowHandle, SW_HIDE);
+ return 0;
+
+ case WM_DESTROY:
+ DestroyWindow (hwnd);
+ PostQuitMessage (0);
+
+ HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);
+
+ ExitThread (0);
+
+ default:
+ break;
+ };
+
+ return DefWindowProc (hwnd, iMsg, wParam, lParam);
+}
+
+
+/**
+ This thread simulates the end of WinMain () aplication. Each Winow nededs
+ to process it's events. The messages are dispatched to
+ WinNtGopThreadWindowProc ().
+ Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
+ are running in a seperate thread. We have to do this to process the events.
+
+ @param lpParameter Handle of window to manage.
+
+ @return if a WM_QUIT message is returned exit.
+
+**/
+DWORD
+WINAPI
+WinNtGopThreadWinMain (
+ LPVOID lpParameter
+ )
+{
+ MSG Message;
+ GRAPHICS_PRIVATE_DATA *Private;
+ RECT Rect;
+
+ Private = (GRAPHICS_PRIVATE_DATA *) lpParameter;
+ ASSERT (NULL != Private);
+
+ //
+ // Since each thread has unique private data, save the private data in Thread
+ // Local Storage slot. Then the shared global mTlsIndex can be used to get
+ // thread specific context.
+ //
+ TlsSetValue (mTlsIndex, Private);
+
+ Private->ThreadId = GetCurrentThreadId ();
+
+ Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);
+ Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;
+ Private->WindowsClass.cbClsExtra = 0;
+ Private->WindowsClass.cbWndExtra = 0;
+ Private->WindowsClass.hInstance = NULL;
+ Private->WindowsClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+ Private->WindowsClass.hCursor = LoadCursor (NULL, IDC_ARROW);
+ Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;
+ Private->WindowsClass.lpszMenuName = NULL;
+ Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;
+ Private->WindowsClass.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
+
+ //
+ // Use 100 x 100 as initial Window size.
+ //
+ Private->Width = 100;
+ Private->Height = 100;
+
+
+ //
+ // This call will fail after the first time, but thats O.K. since we only need
+ // WIN_NT_GOP_CLASS_NAME to exist to create the window.
+ //
+ // Note: Multiple instances of this DLL will use the same instance of this
+ // Class, including the callback function, unless the Class is unregistered and
+ // successfully registered again.
+ //
+ RegisterClassEx (&Private->WindowsClass);
+
+ //
+ // Setting Rect values to allow for the AdjustWindowRect to provide
+ // us the correct sizes for the client area when doing the CreateWindowEx
+ //
+ Rect.top = 0;
+ Rect.bottom = Private->Height;
+ Rect.left = 0;
+ Rect.right = Private->Width;
+
+ AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
+
+ Private->WindowHandle = CreateWindowEx (
+ 0,
+ WIN_NT_GOP_CLASS_NAME,
+ Private->WindowName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ Rect.right - Rect.left,
+ Rect.bottom - Rect.top,
+ NULL,
+ NULL,
+ NULL,
+ (VOID **)&Private
+ );
+
+ //
+ // The reset of this thread is the standard winows program. We need a sperate
+ // thread since we must process the message loop to make windows act like
+ // windows.
+ //
+
+ ShowWindow (Private->WindowHandle, SW_SHOW);
+ UpdateWindow (Private->WindowHandle);
+
+ //
+ // Let the main thread get some work done
+ //
+ ReleaseSemaphore (Private->ThreadInited, 1, NULL);
+
+ //
+ // This is the message loop that all Windows programs need.
+ //
+ while (GetMessage (&Message, Private->WindowHandle, 0, 0)) {
+ TranslateMessage (&Message);
+ DispatchMessage (&Message);
+ }
+
+ return (DWORD)Message.wParam;
+}
+
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param HorizontalResolution TODO: add argument description
+ @param VerticalResolution TODO: add argument description
+ @param ColorDepth TODO: add argument description
+ @param RefreshRate TODO: add argument description
+
+ @return TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+WinNtGraphicsWindowOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ )
+{
+ DWORD NewThreadId;
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = AllocateZeroPool (sizeof (*Private));
+
+ GopPrivateCreateQ (Private, &Private->QueueForRead);
+
+ Private->GraphicsWindowIo.Size = WinNtWndSize;
+ Private->GraphicsWindowIo.CheckKey = WinNtWndCheckKey;
+ Private->GraphicsWindowIo.GetKey = WinNtWndGetKey;
+ Private->GraphicsWindowIo.KeySetState = WinNtWndKeySetState;
+ Private->GraphicsWindowIo.RegisterKeyNotify = WinNtWndRegisterKeyNotify;
+ Private->GraphicsWindowIo.Blt = WinNtWndBlt;
+ Private->GraphicsWindowIo.CheckPointer = WinNtWndCheckPointer;
+ Private->GraphicsWindowIo.GetPointerState = WinNtWndGetPointerState;
+
+ Private->WindowName = This->ConfigString;
+ //
+ // Initialize a Thread Local Storge variable slot. We use TLS to get the
+ // correct Private data instance into the windows thread.
+ //
+ if (mTlsIndex == TLS_OUT_OF_INDEXES) {
+ ASSERT (0 == mTlsIndexUseCount);
+ mTlsIndex = TlsAlloc ();
+ }
+
+ //
+ // always increase the use count!
+ //
+ mTlsIndexUseCount++;
+
+ Private->ThreadInited = CreateSemaphore (NULL, 0, 1, NULL);
+ Private->ThreadHandle = CreateThread (
+ NULL,
+ 0,
+ WinNtGopThreadWinMain,
+ (VOID *) Private,
+ 0,
+ &NewThreadId
+ );
+
+ //
+ // The other thread has entered the windows message loop so we can
+ // continue our initialization.
+ //
+ WaitForSingleObject (Private->ThreadInited, INFINITE);
+ CloseHandle (Private->ThreadInited);
+
+ This->Private = Private;
+ This->Interface = &Private->GraphicsWindowIo;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+WinNtGraphicsWindowClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+)
+{
+ GRAPHICS_PRIVATE_DATA *Private;
+
+ Private = (GRAPHICS_PRIVATE_DATA *)This->Private;
+
+ //
+ // BugBug: Shutdown GOP Hardware and any child devices.
+ //
+ SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
+ CloseHandle (Private->ThreadHandle);
+
+ mTlsIndexUseCount--;
+
+ //
+ // The callback function for another window could still be called,
+ // so we need to make sure there are no more users of mTlsIndex.
+ //
+ if (0 == mTlsIndexUseCount) {
+ ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
+
+ TlsFree (mTlsIndex);
+ mTlsIndex = TLS_OUT_OF_INDEXES;
+
+ UnregisterClass (
+ Private->WindowsClass.lpszClassName,
+ Private->WindowsClass.hInstance
+ );
+ }
+
+
+ GopPrivateDestroyQ (Private, &Private->QueueForRead);
+ return EFI_SUCCESS;
+}
+
+
+EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo = {
+ &gEmuGraphicsWindowProtocolGuid,
+ NULL,
+ NULL,
+ 0,
+ WinNtGraphicsWindowOpen,
+ WinNtGraphicsWindowClose,
+ NULL
+};
diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c
index 22399f18b9..f8d21d26d9 100644
--- a/EmulatorPkg/Win/Host/WinHost.c
+++ b/EmulatorPkg/Win/Host/WinHost.c
@@ -424,6 +424,11 @@ Returns:
//
AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
+ //
+ // Emulator Bus Driver Thunks
+ //
+ AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
+
//
// Allocate space for gSystemMemory Array
//
diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h
index c73ba17e74..3dc6a7e641 100644
--- a/EmulatorPkg/Win/Host/WinHost.h
+++ b/EmulatorPkg/Win/Host/WinHost.h
@@ -197,4 +197,5 @@ SecInitializeThunk (
VOID
);
extern EMU_THUNK_PROTOCOL gEmuThunkProtocol;
+extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo;
#endif
\ No newline at end of file
diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
index 544e775c49..b62791bcfa 100644
--- a/EmulatorPkg/Win/Host/WinHost.inf
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -30,6 +30,9 @@ [Defines]
[Sources]
WinMemoryAllocationLib.c
+ WinGopInput.c
+ WinGopScreen.c
+ WinGop.h
WinThunk.c
WinHost.h
WinHost.c
@@ -55,6 +58,9 @@ [LibraryClasses]
[Ppis]
gEmuThunkPpiGuid
+[Protocols]
+ gEmuIoThunkProtocolGuid
+ gEmuGraphicsWindowProtocolGuid
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
@@ -62,6 +68,7 @@ [Pcd]
gEmulatorPkgTokenSpaceGuid.PcdEmuFirmwareVolume
gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+ gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
[BuildOptions]
--
2.16.1.windows.1
next prev parent reply other threads:[~2018-08-23 9:51 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-08-23 9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
2018-08-23 9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
2018-08-23 9:52 ` [PATCH 02/12] EmulatorPkg/Win: Add Windows host support Ruiyu Ni
2018-08-23 9:52 ` [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging Ruiyu Ni
2018-08-23 9:52 ` [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console Ruiyu Ni
2018-08-23 9:52 ` Ruiyu Ni [this message]
2018-08-23 9:52 ` [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support Ruiyu Ni
2018-08-23 9:52 ` [PATCH 07/12] EmulatorPkg/Win: Add RTC support Ruiyu Ni
2018-08-23 9:52 ` [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support Ruiyu Ni
2018-08-23 9:52 ` [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support Ruiyu Ni
2018-08-23 9:52 ` [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS Ruiyu Ni
2018-08-23 9:52 ` [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion Ruiyu Ni
2018-08-23 9:52 ` [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory Ruiyu Ni
2018-08-23 9:56 ` [PATCH 00/12] Add WinHost support in EmulatorPkg Ni, Ruiyu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180823095215.274248-6-ruiyu.ni@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox