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