From c9fc89a313e0955d3eb8baf3bbfd8bb7d450ad7c Mon Sep 17 00:00:00 2001 From: klu2 Date: Wed, 27 Jun 2007 06:48:58 +0000 Subject: Add WinNtGop driver into Nt32Pkg git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2784 6f19259b-4bc3-4df7-8a09-765794883524 --- Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c | 1020 ++++++++++++++++++++++++++++++++++ 1 file changed, 1020 insertions(+) create mode 100644 Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c (limited to 'Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c') diff --git a/Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c b/Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c new file mode 100644 index 0000000000..e027071228 --- /dev/null +++ b/Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c @@ -0,0 +1,1020 @@ +/** @file + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + WinNtGopScreen.c + +Abstract: + + This file produces the graphics abstration of GOP. It is called by + WinNtGopDriver.c file which deals with the EFI 1.1 driver model. + This file just does graphics. + + +**/ +// +// The package level header files this module uses +// +#include +#include +// +// The protocols, PPI and GUID defintions for this module +// +#include +#include +#include +#include +#include +#include +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include + +#include "WinNtGop.h" + +EFI_WIN_NT_THUNK_PROTOCOL *mWinNt; +DWORD mTlsIndex = TLS_OUT_OF_INDEXES; +DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex. +static EFI_EVENT mGopScreenExitBootServicesEvent; +GOP_MODE_DATA mGopModeData[] = { + {800, 600, 0, 0}, + {640, 480, 0, 0}, + {720, 400, 0, 0}, + {1024, 768, 0, 0}, + {1280, 1024, 0, 0} + }; + +EFI_STATUS +WinNtGopStartWindow ( + IN GOP_PRIVATE_DATA *Private, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ); + +STATIC +VOID +EFIAPI +KillNtGopThread ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// GOP Protocol Member Functions +// + + +/** + Graphics Output protocol interface to get video mode + + @param This Protocol instance pointer. + @param ModeNumber The mode number to return information on. + @param Info Caller allocated buffer that returns information + about ModeNumber. + @param SizeOfInfo A pointer to the size, in bytes, of the Info + buffer. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small. + @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the + video mode. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +EFI_STATUS +EFIAPI +WinNtGopQuerytMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +{ + GOP_PRIVATE_DATA *Private; + + Private = GOP_PRIVATE_DATA_FROM_THIS (This); + + if (Info == NULL || SizeOfInfo == NULL || (UINTN) ModeNumber >= This->Mode->MaxMode) { + return EFI_INVALID_PARAMETER; + } + + *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + if (*Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + (*Info)->Version = 0; + (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution; + (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution; + (*Info)->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution; + + return EFI_SUCCESS; +} + + +/** + Graphics Output protocol interface to set video mode + + @param This Protocol instance pointer. + @param ModeNumber The mode number to be set. + + @retval EFI_SUCCESS Graphics mode was changed. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request. + @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. + +**/ +EFI_STATUS +EFIAPI +WinNtGopSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ) +{ + EFI_STATUS Status; + GOP_PRIVATE_DATA *Private; + GOP_MODE_DATA *ModeData; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewFillLine; + RECT Rect; + UINTN Size; + UINTN Width; + UINTN Height; + + Private = GOP_PRIVATE_DATA_FROM_THIS (This); + + if (ModeNumber >= This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + if (ModeNumber == This->Mode->Mode) { + return EFI_SUCCESS; + } + + ModeData = &Private->ModeData[ModeNumber]; + This->Mode->Mode = ModeNumber; + Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution; + Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution; + Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution; + + if (Private->HardwareNeedsStarting) { + Status = WinNtGopStartWindow ( + Private, + ModeData->HorizontalResolution, + ModeData->VerticalResolution, + ModeData->ColorDepth, + ModeData->RefreshRate + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Private->HardwareNeedsStarting = FALSE; + } else { + // + // Change the resolution and resize of the window + // + + // + // 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() + // + Private->WinNtThunk->HeapFree (Private->WinNtThunk->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 = ModeData->HorizontalResolution * ModeData->VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc ( + Private->WinNtThunk->GetProcessHeap (), + HEAP_ZERO_MEMORY, + Size + ); + + // + // Update the virtual screen info data structure + // + Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo->bV4Width = ModeData->HorizontalResolution; + Private->VirtualScreenInfo->bV4Height = ModeData->VerticalResolution; + 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 = ModeData->HorizontalResolution; + Rect.bottom = ModeData->VerticalResolution; + + Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); + + Width = Rect.right - Rect.left; + Height = Rect.bottom - Rect.top; + + // + // Retrieve the original window position information + // + Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect); + + // + // Adjust the window size + // + Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, Width, Height, TRUE); + + } + + NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->HorizontalResolution); + if (NewFillLine == NULL) { + return EFI_DEVICE_ERROR; + } + + if (Private->FillLine != NULL) { + FreePool (Private->FillLine); + } + + Private->FillLine = NewFillLine; + + Fill.Red = 0x00; + Fill.Green = 0x00; + Fill.Blue = 0x00; + This->Blt ( + This, + &Fill, + EfiBltVideoFill, + 0, + 0, + 0, + 0, + ModeData->HorizontalResolution, + ModeData->VerticalResolution, + ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + ); + 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 +EFIAPI +WinNtGopBlt ( + 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 + ) +{ + GOP_PRIVATE_DATA *Private; + EFI_TPL OriginalTPL; + 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 = GOP_PRIVATE_DATA_FROM_THIS (This); + + if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + // + // If Delta is zero, then the entire BltBuffer is being used, so Delta + // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, + // the number of bytes in each row can be computed. + // + if (Delta == 0) { + Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + + // + // 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 = This->Mode->Info->VerticalResolution; + HorizontalResolution = This->Mode->Info->HorizontalResolution; + if (BltOperation == EfiBltVideoToBltBuffer) { + + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if (SourceY + Height > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (SourceX + Width > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX]; + CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Width); + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + if (BltOperation == EfiBltVideoFill) { + FillPixel = BltBuffer; + for (Index = 0; Index < Width; Index++) { + Private->FillLine[Index] = *FillPixel; + } + } + + for (Index = 0; Index < Height; Index++) { + if (DestinationY <= SourceY) { + SrcY = SourceY + Index; + DstY = DestinationY + Index; + } else { + SrcY = SourceY + Height - Index - 1; + DstY = DestinationY + Height - Index - 1; + } + + VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + DestinationX]; + switch (BltOperation) { + case EfiBltBufferToVideo: + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + CopyMem (VScreen, Blt, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + break; + + case EfiBltVideoToVideo: + VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX]; + CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + break; + + case EfiBltVideoFill: + CopyMem (VScreen, Private->FillLine, 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 = DestinationX; + Rect.top = DestinationY; + Rect.right = DestinationX + Width; + Rect.bottom = DestinationY + Height; + Private->WinNtThunk->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. + // + + Private->WinNtThunk->UpdateWindow (Private->WindowHandle); + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + +// +// Construction and Destruction functions +// + + +/** + + + @return None + +**/ +// TODO: WinNtIo - add argument and description to function comment +// TODO: EFI_UNSUPPORTED - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +EFI_STATUS +WinNtGopSupported ( + IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo + ) +{ + // + // Check to see if the IO abstraction represents a device type we support. + // + // This would be replaced a check of PCI subsystem ID, etc. + // + if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtGopGuid)) { + return EFI_UNSUPPORTED; + } + + 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 + ) +{ + GOP_PRIVATE_DATA *Private; + UINTN Size; + HDC Handle; + PAINTSTRUCT PaintStruct; + LPARAM Index; + EFI_INPUT_KEY Key; + + // + // 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. + // + Private = mWinNt->TlsGetValue (mTlsIndex); + ASSERT (NULL != Private); + + switch (iMsg) { + case WM_CREATE: + Size = Private->GraphicsOutput.Mode->Info->HorizontalResolution * Private->GraphicsOutput.Mode->Info->VerticalResolution * 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 = Private->WinNtThunk->HeapAlloc ( + Private->WinNtThunk->GetProcessHeap (), + HEAP_ZERO_MEMORY, + Size + ); + + Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); + Private->VirtualScreenInfo->bV4Width = Private->GraphicsOutput.Mode->Info->HorizontalResolution; + Private->VirtualScreenInfo->bV4Height = Private->GraphicsOutput.Mode->Info->VerticalResolution; + 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 = mWinNt->BeginPaint (hwnd, &PaintStruct); + + mWinNt->SetDIBitsToDevice ( + Handle, // Destination Device Context + 0, // Destination X - 0 + 0, // Destination Y - 0 + Private->GraphicsOutput.Mode->Info->HorizontalResolution, // Width + Private->GraphicsOutput.Mode->Info->VerticalResolution, // Height + 0, // Source X + 0, // Source Y + 0, // DIB Start Scan Line + Private->GraphicsOutput.Mode->Info->VerticalResolution, // 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 + ); + + mWinNt->EndPaint (hwnd, &PaintStruct); + return 0; + + // + // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case + // + case WM_SYSKEYDOWN: + Key.ScanCode = 0; + switch (wParam) { + case VK_F10: + Key.ScanCode = SCAN_F10; + Key.UnicodeChar = 0; + GopPrivateAddQ (Private, Key); + return 0; + } + break; + + case WM_KEYDOWN: + Key.ScanCode = 0; + switch (wParam) { + case VK_HOME: Key.ScanCode = SCAN_HOME; break; + case VK_END: Key.ScanCode = SCAN_END; break; + case VK_LEFT: Key.ScanCode = SCAN_LEFT; break; + case VK_RIGHT: Key.ScanCode = SCAN_RIGHT; break; + case VK_UP: Key.ScanCode = SCAN_UP; break; + case VK_DOWN: Key.ScanCode = SCAN_DOWN; break; + case VK_DELETE: Key.ScanCode = SCAN_DELETE; break; + case VK_INSERT: Key.ScanCode = SCAN_INSERT; break; + case VK_PRIOR: Key.ScanCode = SCAN_PAGE_UP; break; + case VK_NEXT: Key.ScanCode = SCAN_PAGE_DOWN; break; + case VK_ESCAPE: Key.ScanCode = SCAN_ESC; break; + + case VK_F1: Key.ScanCode = SCAN_F1; break; + case VK_F2: Key.ScanCode = SCAN_F2; break; + case VK_F3: Key.ScanCode = SCAN_F3; break; + case VK_F4: Key.ScanCode = SCAN_F4; break; + case VK_F5: Key.ScanCode = SCAN_F5; break; + case VK_F6: Key.ScanCode = SCAN_F6; break; + case VK_F7: Key.ScanCode = SCAN_F7; break; + case VK_F8: Key.ScanCode = SCAN_F8; break; + case VK_F9: Key.ScanCode = SCAN_F9; break; + case VK_F11: Key.ScanCode = SCAN_F11; break; + case VK_F12: Key.ScanCode = SCAN_F12; break; + } + + if (Key.ScanCode != 0) { + Key.UnicodeChar = 0; + GopPrivateAddQ (Private, Key); + } + + return 0; + + case WM_CHAR: + // + // The ESC key also generate WM_CHAR. + // + if (wParam == 0x1B) { + return 0; + } + + for (Index = 0; Index < (lParam & 0xffff); Index++) { + if (wParam != 0) { + Key.UnicodeChar = (CHAR16) wParam; + Key.ScanCode = 0; + GopPrivateAddQ (Private, Key); + } + } + + 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. + // + Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE); + return 0; + + case WM_DESTROY: + mWinNt->DestroyWindow (hwnd); + mWinNt->PostQuitMessage (0); + + mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo); + + mWinNt->ExitThread (0); + return 0; + + default: + break; + }; + + return mWinNt->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; + GOP_PRIVATE_DATA *Private; + ATOM Atom; + RECT Rect; + + Private = (GOP_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. + // + Private->WinNtThunk->TlsSetValue (mTlsIndex, Private); + + Private->ThreadId = Private->WinNtThunk->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 = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); + Private->WindowsClass.hCursor = Private->WinNtThunk->LoadCursor (NULL, IDC_ARROW); + Private->WindowsClass.hbrBackground = (HBRUSH) COLOR_WINDOW; + Private->WindowsClass.lpszMenuName = NULL; + Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME; + Private->WindowsClass.hIconSm = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); + + // + // 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. + // + Atom = Private->WinNtThunk->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->GraphicsOutput.Mode->Info->VerticalResolution; + Rect.left = 0; + Rect.right = Private->GraphicsOutput.Mode->Info->HorizontalResolution; + + Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); + + Private->WindowHandle = Private->WinNtThunk->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, + &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. + // + + Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_SHOW); + Private->WinNtThunk->UpdateWindow (Private->WindowHandle); + + // + // Let the main thread get some work done + // + Private->WinNtThunk->ReleaseSemaphore (Private->ThreadInited, 1, NULL); + + // + // This is the message loop that all Windows programs need. + // + while (Private->WinNtThunk->GetMessage (&Message, Private->WindowHandle, 0, 0)) { + Private->WinNtThunk->TranslateMessage (&Message); + Private->WinNtThunk->DispatchMessage (&Message); + } + + return 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 +WinNtGopStartWindow ( + IN GOP_PRIVATE_DATA *Private, + IN UINT32 HorizontalResolution, + IN UINT32 VerticalResolution, + IN UINT32 ColorDepth, + IN UINT32 RefreshRate + ) +{ + EFI_STATUS Status; + DWORD NewThreadId; + + mWinNt = Private->WinNtThunk; + + // + // 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 = Private->WinNtThunk->TlsAlloc (); + } + + // + // always increase the use count! + // + mTlsIndexUseCount++; + + // + // Register to be notified on exit boot services so we can destroy the window. + // + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_CALLBACK, + KillNtGopThread, + Private, + &mGopScreenExitBootServicesEvent + ); + + Private->ThreadInited = Private->WinNtThunk->CreateSemaphore (NULL, 0, 1, NULL); + Private->ThreadHandle = Private->WinNtThunk->CreateThread ( + NULL, + 0, + WinNtGopThreadWinMain, + (VOID *) Private, + 0, + &NewThreadId + ); + + // + // The other thread has entered the windows message loop so we can + // continue our initialization. + // + Private->WinNtThunk->WaitForSingleObject (Private->ThreadInited, INFINITE); + Private->WinNtThunk->CloseHandle (Private->ThreadInited); + + return Status; +} + + +/** + + + @return None + +**/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +EFI_STATUS +WinNtGopConstructor ( + GOP_PRIVATE_DATA *Private + ) +{ + Private->ModeData = mGopModeData; + + Private->GraphicsOutput.QueryMode = WinNtGopQuerytMode; + Private->GraphicsOutput.SetMode = WinNtGopSetMode; + Private->GraphicsOutput.Blt = WinNtGopBlt; + + // + // Allocate buffer for Graphics Output Protocol mode information + // + Private->GraphicsOutput.Mode = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); + if (Private->GraphicsOutput.Mode == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Private->GraphicsOutput.Mode->Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + if (Private->GraphicsOutput.Mode->Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->GraphicsOutput.Mode->MaxMode = sizeof(mGopModeData) / sizeof(GOP_MODE_DATA); + // + // Till now, we have no idea about the window size. + // + Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; + Private->GraphicsOutput.Mode->Info->Version = 0; + Private->GraphicsOutput.Mode->Info->HorizontalResolution = 0; + Private->GraphicsOutput.Mode->Info->VerticalResolution = 0; + Private->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly; + Private->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + Private->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) NULL; + Private->GraphicsOutput.Mode->FrameBufferSize = 0; + + Private->HardwareNeedsStarting = TRUE; + Private->FillLine = NULL; + + WinNtGopInitializeSimpleTextInForWindow (Private); + + return EFI_SUCCESS; +} + + +/** + + + @return None + +**/ +// TODO: Private - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +EFI_STATUS +WinNtGopDestructor ( + GOP_PRIVATE_DATA *Private + ) +{ + UINT32 UnregisterReturn; + + if (!Private->HardwareNeedsStarting) { + // + // BugBug: Shutdown GOP Hardware and any child devices. + // + Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0); + Private->WinNtThunk->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); + + Private->WinNtThunk->TlsFree (mTlsIndex); + mTlsIndex = TLS_OUT_OF_INDEXES; + + UnregisterReturn = Private->WinNtThunk->UnregisterClass ( + Private->WindowsClass.lpszClassName, + Private->WindowsClass.hInstance + ); + } + + WinNtGopDestroySimpleTextInForWindow (Private); + } + + // + // Free graphics output protocol occupied resource + // + if (Private->GraphicsOutput.Mode != NULL) { + if (Private->GraphicsOutput.Mode->Info != NULL) { + FreePool (Private->GraphicsOutput.Mode->Info); + } + FreePool (Private->GraphicsOutput.Mode); + } + + return EFI_SUCCESS; +} + + +/** + This is the GOP screen's callback notification function for exit-boot-services. + All we do here is call WinNtGopDestructor(). + + @param Event not used + @param Context pointer to the Private structure. + + @return None. + +**/ +STATIC +VOID +EFIAPI +KillNtGopThread ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + Status = WinNtGopDestructor (Context); +} -- cgit v1.2.3