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