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