]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c
IntelFrameworkModulePkg: Add AcpiS3SaveDxe driver
[mirror_edk2.git] / Nt32Pkg / WinNtGopDxe / WinNtGopScreen.c
1 /** @file
2
3 Copyright (c) 2006 - 2011, 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 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 case VK_PAUSE: Key->ScanCode = SCAN_PAUSE; break;
139
140 //
141 // Set toggle state
142 //
143 case VK_NUMLOCK:
144 Private->NumLock = (BOOLEAN)(!Private->NumLock);
145 break;
146 case VK_SCROLL:
147 Private->ScrollLock = (BOOLEAN)(!Private->ScrollLock);
148 break;
149 case VK_CAPITAL:
150 Private->CapsLock = (BOOLEAN)(!Private->CapsLock);
151 break;
152 }
153
154 WinNtGopConvertParamToEfiKeyShiftState (Private, wParam, TRUE);
155 }
156
157
158 //
159 // GOP Protocol Member Functions
160 //
161
162
163 /**
164 Graphics Output protocol interface to get video mode
165
166 @param This Protocol instance pointer.
167 @param ModeNumber The mode number to return information on.
168 @param Info Caller allocated buffer that returns information
169 about ModeNumber.
170 @param SizeOfInfo A pointer to the size, in bytes, of the Info
171 buffer.
172
173 @retval EFI_SUCCESS Mode information returned.
174 @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small.
175 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
176 video mode.
177 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
178 @retval EFI_INVALID_PARAMETER One of the input args was NULL.
179
180 **/
181 EFI_STATUS
182 EFIAPI
183 WinNtGopQuerytMode (
184 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
185 IN UINT32 ModeNumber,
186 OUT UINTN *SizeOfInfo,
187 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
188 )
189 {
190 GOP_PRIVATE_DATA *Private;
191
192 Private = GOP_PRIVATE_DATA_FROM_THIS (This);
193
194 if (Info == NULL || SizeOfInfo == NULL || (UINTN) ModeNumber >= This->Mode->MaxMode) {
195 return EFI_INVALID_PARAMETER;
196 }
197
198 *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
199 if (*Info == NULL) {
200 return EFI_OUT_OF_RESOURCES;
201 }
202
203 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
204
205 (*Info)->Version = 0;
206 (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
207 (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
208 (*Info)->PixelFormat = PixelBltOnly;
209 (*Info)->PixelsPerScanLine = (*Info)->HorizontalResolution;
210
211 return EFI_SUCCESS;
212 }
213
214
215 /**
216 Graphics Output protocol interface to set video mode
217
218 @param This Protocol instance pointer.
219 @param ModeNumber The mode number to be set.
220
221 @retval EFI_SUCCESS Graphics mode was changed.
222 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
223 request.
224 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
225
226 **/
227 EFI_STATUS
228 EFIAPI
229 WinNtGopSetMode (
230 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
231 IN UINT32 ModeNumber
232 )
233 {
234 EFI_STATUS Status;
235 GOP_PRIVATE_DATA *Private;
236 GOP_MODE_DATA *ModeData;
237 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Fill;
238 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *NewFillLine;
239 RECT Rect;
240 UINTN Size;
241 UINTN Width;
242 UINTN Height;
243
244 Private = GOP_PRIVATE_DATA_FROM_THIS (This);
245
246 if (ModeNumber >= This->Mode->MaxMode) {
247 return EFI_UNSUPPORTED;
248 }
249
250 ModeData = &Private->ModeData[ModeNumber];
251 This->Mode->Mode = ModeNumber;
252 Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
253 Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution;
254 Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution;
255
256 if (Private->HardwareNeedsStarting) {
257 Status = WinNtGopStartWindow (
258 Private,
259 ModeData->HorizontalResolution,
260 ModeData->VerticalResolution,
261 ModeData->ColorDepth,
262 ModeData->RefreshRate
263 );
264 if (EFI_ERROR (Status)) {
265 return EFI_DEVICE_ERROR;
266 }
267
268 Private->HardwareNeedsStarting = FALSE;
269 } else {
270 //
271 // Change the resolution and resize of the window
272 //
273
274 //
275 // Free the old buffer. We do not save the content of the old buffer since the
276 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.
277 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()
278 //
279 Private->WinNtThunk->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);
280
281 //
282 // Allocate DIB frame buffer directly from NT for performance enhancement
283 // This buffer is the virtual screen/frame buffer. This buffer is not the
284 // same a a frame buffer. The first row of this buffer will be the bottom
285 // line of the image. This is an artifact of the way we draw to the screen.
286 //
287 Size = ModeData->HorizontalResolution * ModeData->VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);
288 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (
289 Private->WinNtThunk->GetProcessHeap (),
290 HEAP_ZERO_MEMORY,
291 Size
292 );
293
294 //
295 // Update the virtual screen info data structure
296 //
297 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
298 Private->VirtualScreenInfo->bV4Width = ModeData->HorizontalResolution;
299 Private->VirtualScreenInfo->bV4Height = ModeData->VerticalResolution;
300 Private->VirtualScreenInfo->bV4Planes = 1;
301 Private->VirtualScreenInfo->bV4BitCount = 32;
302 //
303 // uncompressed
304 //
305 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
306
307 //
308 // The rest of the allocated memory block is the virtual screen buffer
309 //
310 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
311
312 //
313 // Use the AdjuctWindowRect fuction to calculate the real width and height
314 // of the new window including the border and caption
315 //
316 Rect.left = 0;
317 Rect.top = 0;
318 Rect.right = ModeData->HorizontalResolution;
319 Rect.bottom = ModeData->VerticalResolution;
320
321 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
322
323 Width = Rect.right - Rect.left;
324 Height = Rect.bottom - Rect.top;
325
326 //
327 // Retrieve the original window position information
328 //
329 Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect);
330
331 //
332 // Adjust the window size
333 //
334 Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, Width, Height, TRUE);
335
336 }
337
338 NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->HorizontalResolution);
339 if (NewFillLine == NULL) {
340 return EFI_DEVICE_ERROR;
341 }
342
343 if (Private->FillLine != NULL) {
344 FreePool (Private->FillLine);
345 }
346
347 Private->FillLine = NewFillLine;
348
349 Fill.Red = 0x00;
350 Fill.Green = 0x00;
351 Fill.Blue = 0x00;
352 This->Blt (
353 This,
354 &Fill,
355 EfiBltVideoFill,
356 0,
357 0,
358 0,
359 0,
360 ModeData->HorizontalResolution,
361 ModeData->VerticalResolution,
362 ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
363 );
364 return EFI_SUCCESS;
365 }
366
367
368 /**
369 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer
370 onto the graphics screen starting a location (X, Y). (0, 0) is defined as
371 the upper left hand side of the screen. (X, Y) can be outside of the
372 current screen geometry and the BltBuffer will be cliped when it is
373 displayed. X and Y can be negative or positive. If Width or Height is
374 bigger than the current video screen the image will be clipped.
375
376 @param This Protocol instance pointer.
377 @param X X location on graphics screen.
378 @param Y Y location on the graphics screen.
379 @param Width Width of BltBuffer.
380 @param Height Hight of BltBuffer
381 @param BltOperation Operation to perform on BltBuffer and video memory
382 @param BltBuffer Buffer containing data to blt into video buffer.
383 This buffer has a size of
384 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
385 @param SourceX If the BltOperation is a EfiCopyBlt this is the
386 source of the copy. For other BLT operations this
387 argument is not used.
388 @param SourceX If the BltOperation is a EfiCopyBlt this is the
389 source of the copy. For other BLT operations this
390 argument is not used.
391
392 @retval EFI_SUCCESS The palette is updated with PaletteArray.
393 @retval EFI_INVALID_PARAMETER BltOperation is not valid.
394 @retval EFI_DEVICE_ERROR A hardware error occured writting to the video
395 buffer.
396
397 **/
398 // TODO: SourceY - add argument and description to function comment
399 // TODO: DestinationX - add argument and description to function comment
400 // TODO: DestinationY - add argument and description to function comment
401 // TODO: Delta - add argument and description to function comment
402 EFI_STATUS
403 EFIAPI
404 WinNtGopBlt (
405 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
406 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
407 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
408 IN UINTN SourceX,
409 IN UINTN SourceY,
410 IN UINTN DestinationX,
411 IN UINTN DestinationY,
412 IN UINTN Width,
413 IN UINTN Height,
414 IN UINTN Delta OPTIONAL
415 )
416 {
417 GOP_PRIVATE_DATA *Private;
418 EFI_TPL OriginalTPL;
419 UINTN DstY;
420 UINTN SrcY;
421 RGBQUAD *VScreen;
422 RGBQUAD *VScreenSrc;
423 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
424 UINTN Index;
425 RECT Rect;
426 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;
427 UINT32 VerticalResolution;
428 UINT32 HorizontalResolution;
429
430 Private = GOP_PRIVATE_DATA_FROM_THIS (This);
431
432 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
433 return EFI_INVALID_PARAMETER;
434 }
435
436 if (Width == 0 || Height == 0) {
437 return EFI_INVALID_PARAMETER;
438 }
439 //
440 // If Delta is zero, then the entire BltBuffer is being used, so Delta
441 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
442 // the number of bytes in each row can be computed.
443 //
444 if (Delta == 0) {
445 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
446 }
447
448 //
449 // We need to fill the Virtual Screen buffer with the blt data.
450 // The virtual screen is upside down, as the first row is the bootom row of
451 // the image.
452 //
453 VerticalResolution = This->Mode->Info->VerticalResolution;
454 HorizontalResolution = This->Mode->Info->HorizontalResolution;
455 if (BltOperation == EfiBltVideoToBltBuffer) {
456
457 //
458 // Video to BltBuffer: Source is Video, destination is BltBuffer
459 //
460 if (SourceY + Height > VerticalResolution) {
461 return EFI_INVALID_PARAMETER;
462 }
463
464 if (SourceX + Width > HorizontalResolution) {
465 return EFI_INVALID_PARAMETER;
466 }
467 //
468 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
469 // We would not want a timer based event (Cursor, ...) to come in while we are
470 // doing this operation.
471 //
472 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
473
474 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
475 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
476 VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX];
477 CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Width);
478 }
479 } else {
480 //
481 // BltBuffer to Video: Source is BltBuffer, destination is Video
482 //
483 if (DestinationY + Height > VerticalResolution) {
484 return EFI_INVALID_PARAMETER;
485 }
486
487 if (DestinationX + Width > HorizontalResolution) {
488 return EFI_INVALID_PARAMETER;
489 }
490
491 //
492 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
493 // We would not want a timer based event (Cursor, ...) to come in while we are
494 // doing this operation.
495 //
496 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
497
498 if (BltOperation == EfiBltVideoFill) {
499 FillPixel = BltBuffer;
500 for (Index = 0; Index < Width; Index++) {
501 Private->FillLine[Index] = *FillPixel;
502 }
503 }
504
505 for (Index = 0; Index < Height; Index++) {
506 if (DestinationY <= SourceY) {
507 SrcY = SourceY + Index;
508 DstY = DestinationY + Index;
509 } else {
510 SrcY = SourceY + Height - Index - 1;
511 DstY = DestinationY + Height - Index - 1;
512 }
513
514 VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + DestinationX];
515 switch (BltOperation) {
516 case EfiBltBufferToVideo:
517 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
518 CopyMem (VScreen, Blt, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
519 break;
520
521 case EfiBltVideoToVideo:
522 VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX];
523 CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
524 break;
525
526 case EfiBltVideoFill:
527 CopyMem (VScreen, Private->FillLine, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
528 break;
529 }
530 }
531 }
532
533 if (BltOperation != EfiBltVideoToBltBuffer) {
534 //
535 // Mark the area we just blted as Invalid so WM_PAINT will update.
536 //
537 Rect.left = DestinationX;
538 Rect.top = DestinationY;
539 Rect.right = DestinationX + Width;
540 Rect.bottom = DestinationY + Height;
541 Private->WinNtThunk->InvalidateRect (Private->WindowHandle, &Rect, FALSE);
542
543 //
544 // Send the WM_PAINT message to the thread that is drawing the window. We
545 // are in the main thread and the window drawing is in a child thread.
546 // There is a child thread per window. We have no CriticalSection or Mutex
547 // since we write the data and the other thread displays the data. While
548 // we may miss some data for a short period of time this is no different than
549 // a write combining on writes to a frame buffer.
550 //
551
552 Private->WinNtThunk->UpdateWindow (Private->WindowHandle);
553 }
554
555 gBS->RestoreTPL (OriginalTPL);
556
557 return EFI_SUCCESS;
558 }
559
560 //
561 // Construction and Destruction functions
562 //
563
564
565 /**
566
567
568 @return None
569
570 **/
571 // TODO: WinNtIo - add argument and description to function comment
572 // TODO: EFI_UNSUPPORTED - add return value to function comment
573 // TODO: EFI_SUCCESS - add return value to function comment
574 EFI_STATUS
575 WinNtGopSupported (
576 IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo
577 )
578 {
579 //
580 // Check to see if the IO abstraction represents a device type we support.
581 //
582 // This would be replaced a check of PCI subsystem ID, etc.
583 //
584 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtGopGuid)) {
585 return EFI_UNSUPPORTED;
586 }
587
588 return EFI_SUCCESS;
589 }
590
591
592 /**
593 Win32 Windows event handler.
594
595 See Win32 Book
596
597 @return See Win32 Book
598
599 **/
600 // TODO: hwnd - add argument and description to function comment
601 // TODO: iMsg - add argument and description to function comment
602 // TODO: wParam - add argument and description to function comment
603 // TODO: lParam - add argument and description to function comment
604 LRESULT
605 CALLBACK
606 WinNtGopThreadWindowProc (
607 IN HWND hwnd,
608 IN UINT iMsg,
609 IN WPARAM wParam,
610 IN LPARAM lParam
611 )
612 {
613 GOP_PRIVATE_DATA *Private;
614 UINTN Size;
615 HDC Handle;
616 PAINTSTRUCT PaintStruct;
617 LPARAM Index;
618 EFI_INPUT_KEY Key;
619
620 //
621 // BugBug - if there are two instances of this DLL in memory (such as is
622 // the case for ERM), the correct instance of this function may not be called.
623 // This also means that the address of the mTlsIndex value will be wrong, and
624 // the value may be wrong too.
625 //
626
627
628 //
629 // Use mTlsIndex global to get a Thread Local Storage version of Private.
630 // This works since each Gop protocol has a unique Private data instance and
631 // a unique thread.
632 //
633 Private = mWinNt->TlsGetValue (mTlsIndex);
634 ASSERT (NULL != Private);
635
636 switch (iMsg) {
637 case WM_CREATE:
638 Size = Private->GraphicsOutput.Mode->Info->HorizontalResolution * Private->GraphicsOutput.Mode->Info->VerticalResolution * sizeof (RGBQUAD);
639
640 //
641 // Allocate DIB frame buffer directly from NT for performance enhancement
642 // This buffer is the virtual screen/frame buffer. This buffer is not the
643 // same a a frame buffer. The first fow of this buffer will be the bottom
644 // line of the image. This is an artifact of the way we draw to the screen.
645 //
646 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (
647 Private->WinNtThunk->GetProcessHeap (),
648 HEAP_ZERO_MEMORY,
649 Size
650 );
651
652 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);
653 Private->VirtualScreenInfo->bV4Width = Private->GraphicsOutput.Mode->Info->HorizontalResolution;
654 Private->VirtualScreenInfo->bV4Height = Private->GraphicsOutput.Mode->Info->VerticalResolution;
655 Private->VirtualScreenInfo->bV4Planes = 1;
656 Private->VirtualScreenInfo->bV4BitCount = 32;
657 //
658 // uncompressed
659 //
660 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;
661 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);
662 return 0;
663
664 case WM_PAINT:
665 //
666 // I have not found a way to convert hwnd into a Private context. So for
667 // now we use this API to convert hwnd to Private data.
668 //
669
670 Handle = mWinNt->BeginPaint (hwnd, &PaintStruct);
671
672 mWinNt->SetDIBitsToDevice (
673 Handle, // Destination Device Context
674 0, // Destination X - 0
675 0, // Destination Y - 0
676 Private->GraphicsOutput.Mode->Info->HorizontalResolution, // Width
677 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Height
678 0, // Source X
679 0, // Source Y
680 0, // DIB Start Scan Line
681 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Number of scan lines
682 Private->VirtualScreen, // Address of array of DIB bits
683 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info
684 DIB_RGB_COLORS // RGB or palette indexes
685 );
686
687 mWinNt->EndPaint (hwnd, &PaintStruct);
688 return 0;
689
690 //
691 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case
692 // WM_SYSKEYDOWN is posted when F10 is pressed or
693 // holds down ALT key and then presses another key.
694 //
695 case WM_SYSKEYDOWN:
696 Key.ScanCode = 0;
697 switch (wParam) {
698 case VK_F10:
699 Key.ScanCode = SCAN_F10;
700 Key.UnicodeChar = 0;
701 GopPrivateAddKey (Private, Key);
702 return 0;
703 }
704
705 if ((lParam & GOP_ALT_KEY_PRESSED) == GOP_ALT_KEY_PRESSED) {
706 //
707 // ALT is pressed with another key pressed
708 //
709 WinNtGopConvertParamToEfiKey (Private, &wParam, &Key);
710
711 if ((lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {
712 Private->RightAlt = TRUE;
713 } else {
714 Private->LeftAlt = TRUE;
715 }
716
717 if (Private->RightAlt && Private->LeftAlt) {
718 Private->LeftAlt = FALSE;
719 }
720 }
721
722 if (Key.ScanCode != 0) {
723 Key.UnicodeChar = 0;
724 GopPrivateAddKey (Private, Key);
725 }
726
727 return 0;
728
729 case WM_SYSKEYUP:
730 if ((lParam & GOP_ALT_KEY_PRESSED) == GOP_ALT_KEY_PRESSED) {
731 //
732 // ALT is pressed with another key released
733 //
734 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, FALSE);
735 //
736 // Actually ALT key is still held down here.
737 // Change the ALT key state when another key is released
738 // by user because we did not find a better solution to
739 // get a released ALT key.
740 //
741 Private->RightAlt = FALSE;
742 Private->LeftAlt = FALSE;
743 }
744
745 return 0;
746
747
748 case WM_KEYDOWN:
749 Key.ScanCode = 0;
750 WinNtGopConvertParamToEfiKey (Private, &wParam, &Key);
751 if (Key.ScanCode != 0) {
752 Key.UnicodeChar = 0;
753 GopPrivateAddKey (Private, Key);
754 }
755
756 return 0;
757
758 case WM_KEYUP:
759 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, FALSE);
760 return 0;
761
762 case WM_CHAR:
763 //
764 // The ESC key also generate WM_CHAR.
765 //
766 if (wParam == 0x1B) {
767 return 0;
768 }
769
770 for (Index = 0; Index < (lParam & 0xffff); Index++) {
771 if (wParam != 0) {
772 Key.UnicodeChar = (CHAR16) wParam;
773 Key.ScanCode = 0;
774 GopPrivateAddKey (Private, Key);
775 }
776 }
777
778 return 0;
779
780 case WM_CLOSE:
781 //
782 // This close message is issued by user, core is not aware of this,
783 // so don't release the window display resource, just hide the window.
784 //
785 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE);
786 return 0;
787
788 case WM_DESTROY:
789 mWinNt->DestroyWindow (hwnd);
790 mWinNt->PostQuitMessage (0);
791
792 mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);
793
794 mWinNt->ExitThread (0);
795 return 0;
796
797 default:
798 break;
799 };
800
801 return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam);
802 }
803
804
805 /**
806 This thread simulates the end of WinMain () aplication. Each Winow nededs
807 to process it's events. The messages are dispatched to
808 WinNtGopThreadWindowProc ().
809 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
810 are running in a seperate thread. We have to do this to process the events.
811
812 @param lpParameter Handle of window to manage.
813
814 @return if a WM_QUIT message is returned exit.
815
816 **/
817 DWORD
818 WINAPI
819 WinNtGopThreadWinMain (
820 LPVOID lpParameter
821 )
822 {
823 MSG Message;
824 GOP_PRIVATE_DATA *Private;
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 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 (VOID **)&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 if (!Private->HardwareNeedsStarting) {
1054 //
1055 // BugBug: Shutdown GOP Hardware and any child devices.
1056 //
1057 Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
1058 Private->WinNtThunk->CloseHandle (Private->ThreadHandle);
1059
1060 mTlsIndexUseCount--;
1061
1062 //
1063 // The callback function for another window could still be called,
1064 // so we need to make sure there are no more users of mTlsIndex.
1065 //
1066 if (0 == mTlsIndexUseCount) {
1067 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
1068
1069 Private->WinNtThunk->TlsFree (mTlsIndex);
1070 mTlsIndex = TLS_OUT_OF_INDEXES;
1071
1072 Private->WinNtThunk->UnregisterClass (
1073 Private->WindowsClass.lpszClassName,
1074 Private->WindowsClass.hInstance
1075 );
1076 }
1077
1078 WinNtGopDestroySimpleTextInForWindow (Private);
1079 }
1080
1081 //
1082 // Free graphics output protocol occupied resource
1083 //
1084 if (Private->GraphicsOutput.Mode != NULL) {
1085 if (Private->GraphicsOutput.Mode->Info != NULL) {
1086 FreePool (Private->GraphicsOutput.Mode->Info);
1087 }
1088 FreePool (Private->GraphicsOutput.Mode);
1089 }
1090
1091 return EFI_SUCCESS;
1092 }
1093
1094
1095 /**
1096 This is the GOP screen's callback notification function for exit-boot-services.
1097 All we do here is call WinNtGopDestructor().
1098
1099 @param Event not used
1100 @param Context pointer to the Private structure.
1101
1102 @return None.
1103
1104 **/
1105 VOID
1106 EFIAPI
1107 KillNtGopThread (
1108 IN EFI_EVENT Event,
1109 IN VOID *Context
1110 )
1111 {
1112 WinNtGopDestructor (Context);
1113 }