1 /** @file 2 3 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 WinNtGopScreen.c 15 16 Abstract: 17 18 This file produces the graphics abstration of GOP. It is called by 19 WinNtGopDriver.c file which deals with the UEFI 2.0 driver model. 20 This file just does graphics. 21 22 23 **/ 24 25 #include "WinNtGop.h" 26 27 EFI_WIN_NT_THUNK_PROTOCOL *mWinNt; 28 DWORD mTlsIndex = TLS_OUT_OF_INDEXES; 29 DWORD mTlsIndexUseCount = 0; // lets us know when we can free mTlsIndex. 30 EFI_EVENT mGopScreenExitBootServicesEvent; 31 GOP_MODE_DATA mGopModeData[] = { 32 {800, 600, 0, 0}, 33 {640, 480, 0, 0}, 34 {720, 400, 0, 0}, 35 {1024, 768, 0, 0}, 36 {1280, 1024, 0, 0} 37 }; 38 39 EFI_STATUS 40 WinNtGopStartWindow ( 41 IN GOP_PRIVATE_DATA *Private, 42 IN UINT32 HorizontalResolution, 43 IN UINT32 VerticalResolution, 44 IN UINT32 ColorDepth, 45 IN UINT32 RefreshRate 46 ); 47 48 VOID 49 EFIAPI 50 KillNtGopThread ( 51 IN EFI_EVENT Event, 52 IN VOID *Context 53 ); 54 55 BOOLEAN 56 WinNtGopConvertParamToEfiKeyShiftState ( 57 IN GOP_PRIVATE_DATA *Private, 58 IN WPARAM *wParam, 59 IN LPARAM *lParam, 60 IN BOOLEAN Flag 61 ) 62 { 63 switch (*wParam) { 64 // 65 // BUGBUG: Only GetAsyncKeyState() and GetKeyState() can distinguish 66 // left and right Ctrl, and Shift key. 67 // Neither of the two is defined in EFI_WIN_NT_THUNK_PROTOCOL. 68 // Therefor, we can not set the correct Shift state here. 69 // 70 case VK_SHIFT: 71 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) { 72 Private->RightShift = Flag; 73 } else { 74 Private->LeftShift = Flag; 75 } 76 return TRUE; 77 78 case VK_LSHIFT: 79 Private->LeftShift = Flag; 80 return TRUE; 81 82 case VK_RSHIFT: 83 Private->RightShift = Flag; 84 return TRUE; 85 86 case VK_CONTROL: 87 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) { 88 Private->RightCtrl= Flag; 89 } else { 90 Private->LeftCtrl = Flag; 91 } 92 return TRUE; 93 94 case VK_LCONTROL: 95 Private->LeftCtrl = Flag; 96 return TRUE; 97 98 case VK_RCONTROL: 99 Private->RightCtrl = Flag; 100 return TRUE; 101 102 case VK_LWIN: 103 Private->LeftLogo = Flag; 104 return TRUE; 105 106 case VK_RWIN: 107 Private->RightLogo = Flag; 108 return TRUE; 109 110 case VK_APPS: 111 Private->Menu = Flag; 112 return TRUE; 113 // 114 // BUGBUG: PrintScreen/SysRq can not trigger WM_KEYDOWN message, 115 // so SySReq shift state is not supported here. 116 // 117 case VK_PRINT: 118 Private->SysReq = Flag; 119 return TRUE; 120 // 121 // For Alt Keystroke. 122 // 123 case VK_MENU: 124 if ((*lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) { 125 Private->RightAlt = Flag; 126 } else { 127 Private->LeftAlt = Flag; 128 } 129 return TRUE; 130 131 default: 132 return FALSE; 133 } 134 } 135 136 BOOLEAN 137 WinNtGopConvertParamToEfiKey ( 138 IN GOP_PRIVATE_DATA *Private, 139 IN WPARAM *wParam, 140 IN LPARAM *lParam, 141 IN EFI_INPUT_KEY *Key 142 ) 143 { 144 BOOLEAN Flag; 145 Flag = FALSE; 146 switch (*wParam) { 147 case VK_HOME: Key->ScanCode = SCAN_HOME; Flag = TRUE; break; 148 case VK_END: Key->ScanCode = SCAN_END; Flag = TRUE; break; 149 case VK_LEFT: Key->ScanCode = SCAN_LEFT; Flag = TRUE; break; 150 case VK_RIGHT: Key->ScanCode = SCAN_RIGHT; Flag = TRUE; break; 151 case VK_UP: Key->ScanCode = SCAN_UP; Flag = TRUE; break; 152 case VK_DOWN: Key->ScanCode = SCAN_DOWN; Flag = TRUE; break; 153 case VK_DELETE: Key->ScanCode = SCAN_DELETE; Flag = TRUE; break; 154 case VK_INSERT: Key->ScanCode = SCAN_INSERT; Flag = TRUE; break; 155 case VK_PRIOR: Key->ScanCode = SCAN_PAGE_UP; Flag = TRUE; break; 156 case VK_NEXT: Key->ScanCode = SCAN_PAGE_DOWN; Flag = TRUE; break; 157 case VK_ESCAPE: Key->ScanCode = SCAN_ESC; Flag = TRUE; break; 158 159 case VK_F1: Key->ScanCode = SCAN_F1; Flag = TRUE; break; 160 case VK_F2: Key->ScanCode = SCAN_F2; Flag = TRUE; break; 161 case VK_F3: Key->ScanCode = SCAN_F3; Flag = TRUE; break; 162 case VK_F4: Key->ScanCode = SCAN_F4; Flag = TRUE; break; 163 case VK_F5: Key->ScanCode = SCAN_F5; Flag = TRUE; break; 164 case VK_F6: Key->ScanCode = SCAN_F6; Flag = TRUE; break; 165 case VK_F7: Key->ScanCode = SCAN_F7; Flag = TRUE; break; 166 case VK_F8: Key->ScanCode = SCAN_F8; Flag = TRUE; break; 167 case VK_F9: Key->ScanCode = SCAN_F9; Flag = TRUE; break; 168 case VK_F11: Key->ScanCode = SCAN_F11; Flag = TRUE; break; 169 case VK_F12: Key->ScanCode = SCAN_F12; Flag = TRUE; break; 170 171 case VK_F13: Key->ScanCode = SCAN_F13; Flag = TRUE; break; 172 case VK_F14: Key->ScanCode = SCAN_F14; Flag = TRUE; break; 173 case VK_F15: Key->ScanCode = SCAN_F15; Flag = TRUE; break; 174 case VK_F16: Key->ScanCode = SCAN_F16; Flag = TRUE; break; 175 case VK_F17: Key->ScanCode = SCAN_F17; Flag = TRUE; break; 176 case VK_F18: Key->ScanCode = SCAN_F18; Flag = TRUE; break; 177 case VK_F19: Key->ScanCode = SCAN_F19; Flag = TRUE; break; 178 case VK_F20: Key->ScanCode = SCAN_F20; Flag = TRUE; break; 179 case VK_F21: Key->ScanCode = SCAN_F21; Flag = TRUE; break; 180 case VK_F22: Key->ScanCode = SCAN_F22; Flag = TRUE; break; 181 case VK_F23: Key->ScanCode = SCAN_F23; Flag = TRUE; break; 182 case VK_F24: Key->ScanCode = SCAN_F24; Flag = TRUE; break; 183 case VK_PAUSE: Key->ScanCode = SCAN_PAUSE; Flag = TRUE; break; 184 185 // 186 // Set toggle state 187 // 188 case VK_NUMLOCK: 189 Private->NumLock = (BOOLEAN)(!Private->NumLock); 190 Flag = TRUE; 191 break; 192 case VK_SCROLL: 193 Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock); 194 Flag = TRUE; 195 break; 196 case VK_CAPITAL: 197 Private->CapsLock = (BOOLEAN)(!Private->CapsLock); 198 Flag = TRUE; 199 break; 200 } 201 202 return (WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, lParam, TRUE)) == TRUE ? TRUE : Flag; 203 } 204 205 206 // 207 // GOP Protocol Member Functions 208 // 209 210 211 /** 212 Graphics Output protocol interface to get video mode 213 214 @param This Protocol instance pointer. 215 @param ModeNumber The mode number to return information on. 216 @param Info Caller allocated buffer that returns information 217 about ModeNumber. 218 @param SizeOfInfo A pointer to the size, in bytes, of the Info 219 buffer. 220 221 @retval EFI_SUCCESS Mode information returned. 222 @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small. 223 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the 224 video mode. 225 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () 226 @retval EFI_INVALID_PARAMETER One of the input args was NULL. 227 228 **/ 229 EFI_STATUS 230 EFIAPI 231 WinNtGopQuerytMode ( 232 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, 233 IN UINT32 ModeNumber, 234 OUT UINTN *SizeOfInfo, 235 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info 236 ) 237 { 238 GOP_PRIVATE_DATA *Private; 239 240 Private = GOP_PRIVATE_DATA_FROM_THIS (This); 241 242 if (Info == NULL || SizeOfInfo == NULL || (UINTN) ModeNumber >= This->Mode->MaxMode) { 243 return EFI_INVALID_PARAMETER; 244 } 245 246 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 247 if (*Info == NULL) { 248 return EFI_OUT_OF_RESOURCES; 249 } 250 251 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); 252 253 (*Info)->Version = 0; 254 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution; 255 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution; 256 (*Info)->PixelFormat = PixelBltOnly; 257 (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution; 258 259 return EFI_SUCCESS; 260 } 261 262 263 /** 264 Graphics Output protocol interface to set video mode 265 266 @param This Protocol instance pointer. 267 @param ModeNumber The mode number to be set. 268 269 @retval EFI_SUCCESS Graphics mode was changed. 270 @retval EFI_DEVICE_ERROR The device had an error and could not complete the 271 request. 272 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. 273 274 **/ 275 EFI_STATUS 276 EFIAPI 277 WinNtGopSetMode ( 278 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, 279 IN UINT32 ModeNumber 280 ) 281 { 282 EFI_STATUS Status; 283 GOP_PRIVATE_DATA *Private; 284 GOP_MODE_DATA *ModeData; 285 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill; 286 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewFillLine; 287 RECT Rect; 288 UINTN Size; 289 UINTN Width; 290 UINTN Height; 291 292 Private = GOP_PRIVATE_DATA_FROM_THIS (This); 293 294 if (ModeNumber >= This->Mode->MaxMode) { 295 return EFI_UNSUPPORTED; 296 } 297 298 ModeData = &Private->ModeData[ModeNumber]; 299 This->Mode->Mode = ModeNumber; 300 Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution; 301 Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution; 302 Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution; 303 304 if (Private->HardwareNeedsStarting) { 305 Status = WinNtGopStartWindow ( 306 Private, 307 ModeData->HorizontalResolution, 308 ModeData->VerticalResolution, 309 ModeData->ColorDepth, 310 ModeData->RefreshRate 311 ); 312 if (EFI_ERROR (Status)) { 313 return EFI_DEVICE_ERROR; 314 } 315 316 Private->HardwareNeedsStarting = FALSE; 317 } else { 318 // 319 // Change the resolution and resize of the window 320 // 321 322 // 323 // Free the old buffer. We do not save the content of the old buffer since the 324 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec. 325 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode() 326 // 327 Private->WinNtThunk->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo); 328 329 // 330 // Allocate DIB frame buffer directly from NT for performance enhancement 331 // This buffer is the virtual screen/frame buffer. This buffer is not the 332 // same a a frame buffer. The first row of this buffer will be the bottom 333 // line of the image. This is an artifact of the way we draw to the screen. 334 // 335 Size = ModeData->HorizontalResolution * ModeData->VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER); 336 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc ( 337 Private->WinNtThunk->GetProcessHeap (), 338 HEAP_ZERO_MEMORY, 339 Size 340 ); 341 342 // 343 // Update the virtual screen info data structure 344 // 345 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); 346 Private->VirtualScreenInfo->bV4Width = ModeData->HorizontalResolution; 347 Private->VirtualScreenInfo->bV4Height = ModeData->VerticalResolution; 348 Private->VirtualScreenInfo->bV4Planes = 1; 349 Private->VirtualScreenInfo->bV4BitCount = 32; 350 // 351 // uncompressed 352 // 353 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB; 354 355 // 356 // The rest of the allocated memory block is the virtual screen buffer 357 // 358 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1); 359 360 // 361 // Use the AdjuctWindowRect fuction to calculate the real width and height 362 // of the new window including the border and caption 363 // 364 Rect.left = 0; 365 Rect.top = 0; 366 Rect.right = ModeData->HorizontalResolution; 367 Rect.bottom = ModeData->VerticalResolution; 368 369 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); 370 371 Width = Rect.right - Rect.left; 372 Height = Rect.bottom - Rect.top; 373 374 // 375 // Retrieve the original window position information 376 // 377 Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect); 378 379 // 380 // Adjust the window size 381 // 382 Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE); 383 384 } 385 386 NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->HorizontalResolution); 387 if (NewFillLine == NULL) { 388 return EFI_DEVICE_ERROR; 389 } 390 391 if (Private->FillLine != NULL) { 392 FreePool (Private->FillLine); 393 } 394 395 Private->FillLine = NewFillLine; 396 397 Fill.Red = 0x00; 398 Fill.Green = 0x00; 399 Fill.Blue = 0x00; 400 This->Blt ( 401 This, 402 &Fill, 403 EfiBltVideoFill, 404 0, 405 0, 406 0, 407 0, 408 ModeData->HorizontalResolution, 409 ModeData->VerticalResolution, 410 ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) 411 ); 412 return EFI_SUCCESS; 413 } 414 415 416 /** 417 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer 418 onto the graphics screen starting a location (X, Y). (0, 0) is defined as 419 the upper left hand side of the screen. (X, Y) can be outside of the 420 current screen geometry and the BltBuffer will be cliped when it is 421 displayed. X and Y can be negative or positive. If Width or Height is 422 bigger than the current video screen the image will be clipped. 423 424 @param This Protocol instance pointer. 425 @param X X location on graphics screen. 426 @param Y Y location on the graphics screen. 427 @param Width Width of BltBuffer. 428 @param Height Hight of BltBuffer 429 @param BltOperation Operation to perform on BltBuffer and video memory 430 @param BltBuffer Buffer containing data to blt into video buffer. 431 This buffer has a size of 432 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) 433 @param SourceX If the BltOperation is a EfiCopyBlt this is the 434 source of the copy. For other BLT operations this 435 argument is not used. 436 @param SourceX If the BltOperation is a EfiCopyBlt this is the 437 source of the copy. For other BLT operations this 438 argument is not used. 439 440 @retval EFI_SUCCESS The palette is updated with PaletteArray. 441 @retval EFI_INVALID_PARAMETER BltOperation is not valid. 442 @retval EFI_DEVICE_ERROR A hardware error occured writting to the video 443 buffer. 444 445 **/ 446 // TODO: SourceY - add argument and description to function comment 447 // TODO: DestinationX - add argument and description to function comment 448 // TODO: DestinationY - add argument and description to function comment 449 // TODO: Delta - add argument and description to function comment 450 EFI_STATUS 451 EFIAPI 452 WinNtGopBlt ( 453 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, 454 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL 455 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, 456 IN UINTN SourceX, 457 IN UINTN SourceY, 458 IN UINTN DestinationX, 459 IN UINTN DestinationY, 460 IN UINTN Width, 461 IN UINTN Height, 462 IN UINTN Delta OPTIONAL 463 ) 464 { 465 GOP_PRIVATE_DATA *Private; 466 EFI_TPL OriginalTPL; 467 UINTN DstY; 468 UINTN SrcY; 469 RGBQUAD *VScreen; 470 RGBQUAD *VScreenSrc; 471 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; 472 UINTN Index; 473 RECT Rect; 474 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel; 475 UINT32 VerticalResolution; 476 UINT32 HorizontalResolution; 477 478 Private = GOP_PRIVATE_DATA_FROM_THIS (This); 479 480 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) { 481 return EFI_INVALID_PARAMETER; 482 } 483 484 if (Width == 0 || Height == 0) { 485 return EFI_INVALID_PARAMETER; 486 } 487 // 488 // If Delta is zero, then the entire BltBuffer is being used, so Delta 489 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, 490 // the number of bytes in each row can be computed. 491 // 492 if (Delta == 0) { 493 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); 494 } 495 496 // 497 // We need to fill the Virtual Screen buffer with the blt data. 498 // The virtual screen is upside down, as the first row is the bootom row of 499 // the image. 500 // 501 VerticalResolution = This->Mode->Info->VerticalResolution; 502 HorizontalResolution = This->Mode->Info->HorizontalResolution; 503 if (BltOperation == EfiBltVideoToBltBuffer) { 504 505 // 506 // Video to BltBuffer: Source is Video, destination is BltBuffer 507 // 508 if (SourceY + Height > VerticalResolution) { 509 return EFI_INVALID_PARAMETER; 510 } 511 512 if (SourceX + Width > HorizontalResolution) { 513 return EFI_INVALID_PARAMETER; 514 } 515 // 516 // We have to raise to TPL Notify, so we make an atomic write the frame buffer. 517 // We would not want a timer based event (Cursor, ...) to come in while we are 518 // doing this operation. 519 // 520 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); 521 522 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { 523 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); 524 VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX]; 525 CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Width); 526 } 527 } else { 528 // 529 // BltBuffer to Video: Source is BltBuffer, destination is Video 530 // 531 if (DestinationY + Height > VerticalResolution) { 532 return EFI_INVALID_PARAMETER; 533 } 534 535 if (DestinationX + Width > HorizontalResolution) { 536 return EFI_INVALID_PARAMETER; 537 } 538 539 // 540 // We have to raise to TPL Notify, so we make an atomic write the frame buffer. 541 // We would not want a timer based event (Cursor, ...) to come in while we are 542 // doing this operation. 543 // 544 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); 545 546 if (BltOperation == EfiBltVideoFill) { 547 FillPixel = BltBuffer; 548 for (Index = 0; Index < Width; Index++) { 549 Private->FillLine[Index] = *FillPixel; 550 } 551 } 552 553 for (Index = 0; Index < Height; Index++) { 554 if (DestinationY <= SourceY) { 555 SrcY = SourceY + Index; 556 DstY = DestinationY + Index; 557 } else { 558 SrcY = SourceY + Height - Index - 1; 559 DstY = DestinationY + Height - Index - 1; 560 } 561 562 VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + DestinationX]; 563 switch (BltOperation) { 564 case EfiBltBufferToVideo: 565 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); 566 CopyMem (VScreen, Blt, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); 567 break; 568 569 case EfiBltVideoToVideo: 570 VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX]; 571 CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); 572 break; 573 574 case EfiBltVideoFill: 575 CopyMem (VScreen, Private->FillLine, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); 576 break; 577 } 578 } 579 } 580 581 if (BltOperation != EfiBltVideoToBltBuffer) { 582 // 583 // Mark the area we just blted as Invalid so WM_PAINT will update. 584 // 585 Rect.left = (LONG)DestinationX; 586 Rect.top = (LONG)DestinationY; 587 Rect.right = (LONG)(DestinationX + Width); 588 Rect.bottom = (LONG)(DestinationY + Height); 589 Private->WinNtThunk->InvalidateRect (Private->WindowHandle, &Rect, FALSE); 590 591 // 592 // Send the WM_PAINT message to the thread that is drawing the window. We 593 // are in the main thread and the window drawing is in a child thread. 594 // There is a child thread per window. We have no CriticalSection or Mutex 595 // since we write the data and the other thread displays the data. While 596 // we may miss some data for a short period of time this is no different than 597 // a write combining on writes to a frame buffer. 598 // 599 600 Private->WinNtThunk->UpdateWindow (Private->WindowHandle); 601 } 602 603 gBS->RestoreTPL (OriginalTPL); 604 605 return EFI_SUCCESS; 606 } 607 608 // 609 // Construction and Destruction functions 610 // 611 612 613 /** 614 615 616 @return None 617 618 **/ 619 // TODO: WinNtIo - add argument and description to function comment 620 // TODO: EFI_UNSUPPORTED - add return value to function comment 621 // TODO: EFI_SUCCESS - add return value to function comment 622 EFI_STATUS 623 WinNtGopSupported ( 624 IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo 625 ) 626 { 627 // 628 // Check to see if the IO abstraction represents a device type we support. 629 // 630 // This would be replaced a check of PCI subsystem ID, etc. 631 // 632 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtGopGuid)) { 633 return EFI_UNSUPPORTED; 634 } 635 636 return EFI_SUCCESS; 637 } 638 639 640 /** 641 Win32 Windows event handler. 642 643 See Win32 Book 644 645 @return See Win32 Book 646 647 **/ 648 // TODO: hwnd - add argument and description to function comment 649 // TODO: iMsg - add argument and description to function comment 650 // TODO: wParam - add argument and description to function comment 651 // TODO: lParam - add argument and description to function comment 652 LRESULT 653 CALLBACK 654 WinNtGopThreadWindowProc ( 655 IN HWND hwnd, 656 IN UINT iMsg, 657 IN WPARAM wParam, 658 IN LPARAM lParam 659 ) 660 { 661 GOP_PRIVATE_DATA *Private; 662 UINTN Size; 663 HDC Handle; 664 PAINTSTRUCT PaintStruct; 665 LPARAM Index; 666 EFI_INPUT_KEY Key; 667 BOOLEAN AltIsPress; 668 669 // 670 // BugBug - if there are two instances of this DLL in memory (such as is 671 // the case for ERM), the correct instance of this function may not be called. 672 // This also means that the address of the mTlsIndex value will be wrong, and 673 // the value may be wrong too. 674 // 675 676 677 // 678 // Use mTlsIndex global to get a Thread Local Storage version of Private. 679 // This works since each Gop protocol has a unique Private data instance and 680 // a unique thread. 681 // 682 AltIsPress = FALSE; 683 Private = mWinNt->TlsGetValue (mTlsIndex); 684 ASSERT (NULL != Private); 685 686 switch (iMsg) { 687 case WM_CREATE: 688 Size = Private->GraphicsOutput.Mode->Info->HorizontalResolution * Private->GraphicsOutput.Mode->Info->VerticalResolution * sizeof (RGBQUAD); 689 690 // 691 // Allocate DIB frame buffer directly from NT for performance enhancement 692 // This buffer is the virtual screen/frame buffer. This buffer is not the 693 // same a a frame buffer. The first fow of this buffer will be the bottom 694 // line of the image. This is an artifact of the way we draw to the screen. 695 // 696 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc ( 697 Private->WinNtThunk->GetProcessHeap (), 698 HEAP_ZERO_MEMORY, 699 Size 700 ); 701 702 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER); 703 Private->VirtualScreenInfo->bV4Width = Private->GraphicsOutput.Mode->Info->HorizontalResolution; 704 Private->VirtualScreenInfo->bV4Height = Private->GraphicsOutput.Mode->Info->VerticalResolution; 705 Private->VirtualScreenInfo->bV4Planes = 1; 706 Private->VirtualScreenInfo->bV4BitCount = 32; 707 // 708 // uncompressed 709 // 710 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB; 711 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1); 712 return 0; 713 714 case WM_PAINT: 715 // 716 // I have not found a way to convert hwnd into a Private context. So for 717 // now we use this API to convert hwnd to Private data. 718 // 719 720 Handle = mWinNt->BeginPaint (hwnd, &PaintStruct); 721 722 mWinNt->SetDIBitsToDevice ( 723 Handle, // Destination Device Context 724 0, // Destination X - 0 725 0, // Destination Y - 0 726 Private->GraphicsOutput.Mode->Info->HorizontalResolution, // Width 727 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Height 728 0, // Source X 729 0, // Source Y 730 0, // DIB Start Scan Line 731 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Number of scan lines 732 Private->VirtualScreen, // Address of array of DIB bits 733 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info 734 DIB_RGB_COLORS // RGB or palette indexes 735 ); 736 737 mWinNt->EndPaint (hwnd, &PaintStruct); 738 return 0; 739 740 // 741 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case 742 // WM_SYSKEYDOWN is posted when F10 is pressed or 743 // holds down ALT key and then presses another key. 744 // 745 case WM_SYSKEYDOWN: 746 747 Key.ScanCode = 0; 748 Key.UnicodeChar = CHAR_NULL; 749 switch (wParam) { 750 case VK_F10: 751 Key.ScanCode = SCAN_F10; 752 Key.UnicodeChar = CHAR_NULL; 753 GopPrivateAddKey (Private, Key); 754 return 0; 755 } 756 757 // 758 // If ALT or ALT + modifier key is pressed. 759 // 760 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) { 761 if (Key.ScanCode != 0){ 762 // 763 // If ALT is pressed with other ScanCode. 764 // Always revers the left Alt for simple. 765 // 766 Private->LeftAlt = TRUE; 767 } 768 GopPrivateAddKey (Private, Key); 769 // 770 // When Alt is released there is no windoes message, so 771 // clean it after using it. 772 // 773 Private->RightAlt = FALSE; 774 Private->LeftAlt = FALSE; 775 return 0; 776 } 777 AltIsPress = TRUE; 778 779 case WM_CHAR: 780 // 781 // The ESC key also generate WM_CHAR. 782 // 783 if (wParam == 0x1B) { 784 return 0; 785 } 786 787 if (AltIsPress == TRUE) { 788 // 789 // If AltIsPress is true that means the Alt key is pressed. 790 // 791 Private->LeftAlt = TRUE; 792 } 793 for (Index = 0; Index < (lParam & 0xffff); Index++) { 794 if (wParam != 0) { 795 Key.UnicodeChar = (CHAR16) wParam; 796 Key.ScanCode = SCAN_NULL; 797 GopPrivateAddKey (Private, Key); 798 } 799 } 800 if (AltIsPress == TRUE) { 801 // 802 // When Alt is released there is no windoes message, so 803 // clean it after using it. 804 // 805 Private->LeftAlt = FALSE; 806 Private->RightAlt = FALSE; 807 } 808 return 0; 809 810 case WM_SYSKEYUP: 811 // 812 // ALT is pressed with another key released 813 // 814 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE); 815 return 0; 816 817 case WM_KEYDOWN: 818 Key.ScanCode = SCAN_NULL; 819 Key.UnicodeChar = CHAR_NULL; 820 // 821 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR 822 // So if there is no modifier key updated, skip the WM_KEYDOWN even. 823 // 824 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) { 825 // 826 // Support the partial keystroke, add all keydown event into the queue. 827 // 828 GopPrivateAddKey (Private, Key); 829 } 830 return 0; 831 832 case WM_KEYUP: 833 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE); 834 return 0; 835 836 case WM_CLOSE: 837 // 838 // This close message is issued by user, core is not aware of this, 839 // so don't release the window display resource, just hide the window. 840 // 841 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE); 842 return 0; 843 844 case WM_DESTROY: 845 mWinNt->DestroyWindow (hwnd); 846 mWinNt->PostQuitMessage (0); 847 848 mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo); 849 850 mWinNt->ExitThread (0); 851 return 0; 852 853 default: 854 break; 855 }; 856 857 return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam); 858 } 859 860 861 /** 862 This thread simulates the end of WinMain () aplication. Each Winow nededs 863 to process it's events. The messages are dispatched to 864 WinNtGopThreadWindowProc (). 865 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc () 866 are running in a seperate thread. We have to do this to process the events. 867 868 @param lpParameter Handle of window to manage. 869 870 @return if a WM_QUIT message is returned exit. 871 872 **/ 873 DWORD 874 WINAPI 875 WinNtGopThreadWinMain ( 876 LPVOID lpParameter 877 ) 878 { 879 MSG Message; 880 GOP_PRIVATE_DATA *Private; 881 RECT Rect; 882 883 Private = (GOP_PRIVATE_DATA *) lpParameter; 884 ASSERT (NULL != Private); 885 886 // 887 // Since each thread has unique private data, save the private data in Thread 888 // Local Storage slot. Then the shared global mTlsIndex can be used to get 889 // thread specific context. 890 // 891 Private->WinNtThunk->TlsSetValue (mTlsIndex, Private); 892 893 Private->ThreadId = Private->WinNtThunk->GetCurrentThreadId (); 894 895 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX); 896 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 897 Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc; 898 Private->WindowsClass.cbClsExtra = 0; 899 Private->WindowsClass.cbWndExtra = 0; 900 Private->WindowsClass.hInstance = NULL; 901 Private->WindowsClass.hIcon = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); 902 Private->WindowsClass.hCursor = Private->WinNtThunk->LoadCursor (NULL, IDC_ARROW); 903 Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW; 904 Private->WindowsClass.lpszMenuName = NULL; 905 Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME; 906 Private->WindowsClass.hIconSm = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION); 907 908 // 909 // This call will fail after the first time, but thats O.K. since we only need 910 // WIN_NT_GOP_CLASS_NAME to exist to create the window. 911 // 912 // Note: Multiple instances of this DLL will use the same instance of this 913 // Class, including the callback function, unless the Class is unregistered and 914 // successfully registered again. 915 // 916 Private->WinNtThunk->RegisterClassEx (&Private->WindowsClass); 917 918 // 919 // Setting Rect values to allow for the AdjustWindowRect to provide 920 // us the correct sizes for the client area when doing the CreateWindowEx 921 // 922 Rect.top = 0; 923 Rect.bottom = Private->GraphicsOutput.Mode->Info->VerticalResolution; 924 Rect.left = 0; 925 Rect.right = Private->GraphicsOutput.Mode->Info->HorizontalResolution; 926 927 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0); 928 929 Private->WindowHandle = Private->WinNtThunk->CreateWindowEx ( 930 0, 931 WIN_NT_GOP_CLASS_NAME, 932 Private->WindowName, 933 WS_OVERLAPPEDWINDOW, 934 CW_USEDEFAULT, 935 CW_USEDEFAULT, 936 Rect.right - Rect.left, 937 Rect.bottom - Rect.top, 938 NULL, 939 NULL, 940 NULL, 941 (VOID **)&Private 942 ); 943 944 // 945 // The reset of this thread is the standard winows program. We need a sperate 946 // thread since we must process the message loop to make windows act like 947 // windows. 948 // 949 950 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_SHOW); 951 Private->WinNtThunk->UpdateWindow (Private->WindowHandle); 952 953 // 954 // Let the main thread get some work done 955 // 956 Private->WinNtThunk->ReleaseSemaphore (Private->ThreadInited, 1, NULL); 957 958 // 959 // This is the message loop that all Windows programs need. 960 // 961 while (Private->WinNtThunk->GetMessage (&Message, Private->WindowHandle, 0, 0)) { 962 Private->WinNtThunk->TranslateMessage (&Message); 963 Private->WinNtThunk->DispatchMessage (&Message); 964 } 965 966 return (DWORD)Message.wParam; 967 } 968 969 970 /** 971 TODO: Add function description 972 973 @param Private TODO: add argument description 974 @param HorizontalResolution TODO: add argument description 975 @param VerticalResolution TODO: add argument description 976 @param ColorDepth TODO: add argument description 977 @param RefreshRate TODO: add argument description 978 979 @return TODO: add return values 980 981 **/ 982 EFI_STATUS 983 WinNtGopStartWindow ( 984 IN GOP_PRIVATE_DATA *Private, 985 IN UINT32 HorizontalResolution, 986 IN UINT32 VerticalResolution, 987 IN UINT32 ColorDepth, 988 IN UINT32 RefreshRate 989 ) 990 { 991 EFI_STATUS Status; 992 DWORD NewThreadId; 993 994 mWinNt = Private->WinNtThunk; 995 996 // 997 // Initialize a Thread Local Storge variable slot. We use TLS to get the 998 // correct Private data instance into the windows thread. 999 // 1000 if (mTlsIndex == TLS_OUT_OF_INDEXES) { 1001 ASSERT (0 == mTlsIndexUseCount); 1002 mTlsIndex = Private->WinNtThunk->TlsAlloc (); 1003 } 1004 1005 // 1006 // always increase the use count! 1007 // 1008 mTlsIndexUseCount++; 1009 1010 // 1011 // Register to be notified on exit boot services so we can destroy the window. 1012 // 1013 Status = gBS->CreateEventEx ( 1014 EVT_NOTIFY_SIGNAL, 1015 TPL_CALLBACK, 1016 KillNtGopThread, 1017 Private, 1018 &gEfiEventExitBootServicesGuid, 1019 &mGopScreenExitBootServicesEvent 1020 ); 1021 1022 Private->ThreadInited = Private->WinNtThunk->CreateSemaphore (NULL, 0, 1, NULL); 1023 Private->ThreadHandle = Private->WinNtThunk->CreateThread ( 1024 NULL, 1025 0, 1026 WinNtGopThreadWinMain, 1027 (VOID *) Private, 1028 0, 1029 &NewThreadId 1030 ); 1031 1032 // 1033 // The other thread has entered the windows message loop so we can 1034 // continue our initialization. 1035 // 1036 Private->WinNtThunk->WaitForSingleObject (Private->ThreadInited, INFINITE); 1037 Private->WinNtThunk->CloseHandle (Private->ThreadInited); 1038 1039 return Status; 1040 } 1041 1042 1043 /** 1044 1045 1046 @return None 1047 1048 **/ 1049 // TODO: Private - add argument and description to function comment 1050 // TODO: EFI_SUCCESS - add return value to function comment 1051 EFI_STATUS 1052 WinNtGopConstructor ( 1053 GOP_PRIVATE_DATA *Private 1054 ) 1055 { 1056 Private->ModeData = mGopModeData; 1057 1058 Private->GraphicsOutput.QueryMode = WinNtGopQuerytMode; 1059 Private->GraphicsOutput.SetMode = WinNtGopSetMode; 1060 Private->GraphicsOutput.Blt = WinNtGopBlt; 1061 1062 // 1063 // Allocate buffer for Graphics Output Protocol mode information 1064 // 1065 Private->GraphicsOutput.Mode = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); 1066 if (Private->GraphicsOutput.Mode == NULL) { 1067 return EFI_OUT_OF_RESOURCES; 1068 } 1069 Private->GraphicsOutput.Mode->Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); 1070 if (Private->GraphicsOutput.Mode->Info == NULL) { 1071 return EFI_OUT_OF_RESOURCES; 1072 } 1073 1074 Private->GraphicsOutput.Mode->MaxMode = sizeof(mGopModeData) / sizeof(GOP_MODE_DATA); 1075 // 1076 // Till now, we have no idea about the window size. 1077 // 1078 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; 1079 Private->GraphicsOutput.Mode->Info->Version = 0; 1080 Private->GraphicsOutput.Mode->Info->HorizontalResolution = 0; 1081 Private->GraphicsOutput.Mode->Info->VerticalResolution = 0; 1082 Private->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly; 1083 Private->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); 1084 Private->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL; 1085 Private->GraphicsOutput.Mode->FrameBufferSize = 0; 1086 1087 Private->HardwareNeedsStarting = TRUE; 1088 Private->FillLine = NULL; 1089 1090 WinNtGopInitializeSimpleTextInForWindow (Private); 1091 1092 return EFI_SUCCESS; 1093 } 1094 1095 1096 /** 1097 1098 1099 @return None 1100 1101 **/ 1102 // TODO: Private - add argument and description to function comment 1103 // TODO: EFI_SUCCESS - add return value to function comment 1104 EFI_STATUS 1105 WinNtGopDestructor ( 1106 GOP_PRIVATE_DATA *Private 1107 ) 1108 { 1109 if (!Private->HardwareNeedsStarting) { 1110 // 1111 // BugBug: Shutdown GOP Hardware and any child devices. 1112 // 1113 Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0); 1114 Private->WinNtThunk->CloseHandle (Private->ThreadHandle); 1115 1116 mTlsIndexUseCount--; 1117 1118 // 1119 // The callback function for another window could still be called, 1120 // so we need to make sure there are no more users of mTlsIndex. 1121 // 1122 if (0 == mTlsIndexUseCount) { 1123 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex); 1124 1125 Private->WinNtThunk->TlsFree (mTlsIndex); 1126 mTlsIndex = TLS_OUT_OF_INDEXES; 1127 1128 Private->WinNtThunk->UnregisterClass ( 1129 Private->WindowsClass.lpszClassName, 1130 Private->WindowsClass.hInstance 1131 ); 1132 } 1133 1134 WinNtGopDestroySimpleTextInForWindow (Private); 1135 } 1136 1137 // 1138 // Free graphics output protocol occupied resource 1139 // 1140 if (Private->GraphicsOutput.Mode != NULL) { 1141 if (Private->GraphicsOutput.Mode->Info != NULL) { 1142 FreePool (Private->GraphicsOutput.Mode->Info); 1143 } 1144 FreePool (Private->GraphicsOutput.Mode); 1145 } 1146 1147 return EFI_SUCCESS; 1148 } 1149 1150 1151 /** 1152 This is the GOP screen's callback notification function for exit-boot-services. 1153 All we do here is call WinNtGopDestructor(). 1154 1155 @param Event not used 1156 @param Context pointer to the Private structure. 1157 1158 @return None. 1159 1160 **/ 1161 VOID 1162 EFIAPI 1163 KillNtGopThread ( 1164 IN EFI_EVENT Event, 1165 IN VOID *Context 1166 ) 1167 { 1168 WinNtGopDestructor (Context); 1169 } 1170