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