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