1 /** @file
2
3 Copyright (c) 2006 - 2013, 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
WinNtGopConvertParamToEfiKeyShiftState(IN GOP_PRIVATE_DATA * Private,IN WPARAM * wParam,IN LPARAM * lParam,IN BOOLEAN Flag)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
WinNtGopConvertParamToEfiKey(IN GOP_PRIVATE_DATA * Private,IN WPARAM * wParam,IN LPARAM * lParam,IN EFI_INPUT_KEY * Key)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
WinNtGopQuerytMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber,OUT UINTN * SizeOfInfo,OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION ** Info)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
WinNtGopSetMode(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN UINT32 ModeNumber)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, (INT32)Width, (INT32)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
WinNtGopBlt(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)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 = (LONG)DestinationX;
586 Rect.top = (LONG)DestinationY;
587 Rect.right = (LONG)(DestinationX + Width);
588 Rect.bottom = (LONG)(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
WinNtGopSupported(IN EFI_WIN_NT_IO_PROTOCOL * WinNtIo)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
WinNtGopThreadWindowProc(IN HWND hwnd,IN UINT iMsg,IN WPARAM wParam,IN LPARAM lParam)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 Key.UnicodeChar = CHAR_NULL;
820 //
821 // A value key press will cause a WM_KEYDOWN first, then cause a WM_CHAR
822 // So if there is no modifier key updated, skip the WM_KEYDOWN even.
823 //
824 if (WinNtGopConvertParamToEfiKey (Private, &wParam, &lParam, &Key)) {
825 //
826 // Support the partial keystroke, add all keydown event into the queue.
827 //
828 GopPrivateAddKey (Private, Key);
829 }
830 return 0;
831
832 case WM_KEYUP:
833 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, &lParam, FALSE);
834 return 0;
835
836 case WM_CLOSE:
837 //
838 // This close message is issued by user, core is not aware of this,
839 // so don't release the window display resource, just hide the window.
840 //
841 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE);
842 return 0;
843
844 case WM_DESTROY:
845 mWinNt->DestroyWindow (hwnd);
846 mWinNt->PostQuitMessage (0);
847
848 mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);
849
850 mWinNt->ExitThread (0);
851 return 0;
852
853 default:
854 break;
855 };
856
857 return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam);
858 }
859
860
861 /**
862 This thread simulates the end of WinMain () aplication. Each Winow nededs
863 to process it's events. The messages are dispatched to
864 WinNtGopThreadWindowProc ().
865 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()
866 are running in a seperate thread. We have to do this to process the events.
867
868 @param lpParameter Handle of window to manage.
869
870 @return if a WM_QUIT message is returned exit.
871
872 **/
873 DWORD
874 WINAPI
WinNtGopThreadWinMain(LPVOID lpParameter)875 WinNtGopThreadWinMain (
876 LPVOID lpParameter
877 )
878 {
879 MSG Message;
880 GOP_PRIVATE_DATA *Private;
881 RECT Rect;
882
883 Private = (GOP_PRIVATE_DATA *) lpParameter;
884 ASSERT (NULL != Private);
885
886 //
887 // Since each thread has unique private data, save the private data in Thread
888 // Local Storage slot. Then the shared global mTlsIndex can be used to get
889 // thread specific context.
890 //
891 Private->WinNtThunk->TlsSetValue (mTlsIndex, Private);
892
893 Private->ThreadId = Private->WinNtThunk->GetCurrentThreadId ();
894
895 Private->WindowsClass.cbSize = sizeof (WNDCLASSEX);
896 Private->WindowsClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
897 Private->WindowsClass.lpfnWndProc = WinNtGopThreadWindowProc;
898 Private->WindowsClass.cbClsExtra = 0;
899 Private->WindowsClass.cbWndExtra = 0;
900 Private->WindowsClass.hInstance = NULL;
901 Private->WindowsClass.hIcon = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION);
902 Private->WindowsClass.hCursor = Private->WinNtThunk->LoadCursor (NULL, IDC_ARROW);
903 Private->WindowsClass.hbrBackground = (HBRUSH)(UINTN)COLOR_WINDOW;
904 Private->WindowsClass.lpszMenuName = NULL;
905 Private->WindowsClass.lpszClassName = WIN_NT_GOP_CLASS_NAME;
906 Private->WindowsClass.hIconSm = Private->WinNtThunk->LoadIcon (NULL, IDI_APPLICATION);
907
908 //
909 // This call will fail after the first time, but thats O.K. since we only need
910 // WIN_NT_GOP_CLASS_NAME to exist to create the window.
911 //
912 // Note: Multiple instances of this DLL will use the same instance of this
913 // Class, including the callback function, unless the Class is unregistered and
914 // successfully registered again.
915 //
916 Private->WinNtThunk->RegisterClassEx (&Private->WindowsClass);
917
918 //
919 // Setting Rect values to allow for the AdjustWindowRect to provide
920 // us the correct sizes for the client area when doing the CreateWindowEx
921 //
922 Rect.top = 0;
923 Rect.bottom = Private->GraphicsOutput.Mode->Info->VerticalResolution;
924 Rect.left = 0;
925 Rect.right = Private->GraphicsOutput.Mode->Info->HorizontalResolution;
926
927 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);
928
929 Private->WindowHandle = Private->WinNtThunk->CreateWindowEx (
930 0,
931 WIN_NT_GOP_CLASS_NAME,
932 Private->WindowName,
933 WS_OVERLAPPEDWINDOW,
934 CW_USEDEFAULT,
935 CW_USEDEFAULT,
936 Rect.right - Rect.left,
937 Rect.bottom - Rect.top,
938 NULL,
939 NULL,
940 NULL,
941 (VOID **)&Private
942 );
943
944 //
945 // The reset of this thread is the standard winows program. We need a sperate
946 // thread since we must process the message loop to make windows act like
947 // windows.
948 //
949
950 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_SHOW);
951 Private->WinNtThunk->UpdateWindow (Private->WindowHandle);
952
953 //
954 // Let the main thread get some work done
955 //
956 Private->WinNtThunk->ReleaseSemaphore (Private->ThreadInited, 1, NULL);
957
958 //
959 // This is the message loop that all Windows programs need.
960 //
961 while (Private->WinNtThunk->GetMessage (&Message, Private->WindowHandle, 0, 0)) {
962 Private->WinNtThunk->TranslateMessage (&Message);
963 Private->WinNtThunk->DispatchMessage (&Message);
964 }
965
966 return (DWORD)Message.wParam;
967 }
968
969
970 /**
971 TODO: Add function description
972
973 @param Private TODO: add argument description
974 @param HorizontalResolution TODO: add argument description
975 @param VerticalResolution TODO: add argument description
976 @param ColorDepth TODO: add argument description
977 @param RefreshRate TODO: add argument description
978
979 @return TODO: add return values
980
981 **/
982 EFI_STATUS
WinNtGopStartWindow(IN GOP_PRIVATE_DATA * Private,IN UINT32 HorizontalResolution,IN UINT32 VerticalResolution,IN UINT32 ColorDepth,IN UINT32 RefreshRate)983 WinNtGopStartWindow (
984 IN GOP_PRIVATE_DATA *Private,
985 IN UINT32 HorizontalResolution,
986 IN UINT32 VerticalResolution,
987 IN UINT32 ColorDepth,
988 IN UINT32 RefreshRate
989 )
990 {
991 EFI_STATUS Status;
992 DWORD NewThreadId;
993
994 mWinNt = Private->WinNtThunk;
995
996 //
997 // Initialize a Thread Local Storge variable slot. We use TLS to get the
998 // correct Private data instance into the windows thread.
999 //
1000 if (mTlsIndex == TLS_OUT_OF_INDEXES) {
1001 ASSERT (0 == mTlsIndexUseCount);
1002 mTlsIndex = Private->WinNtThunk->TlsAlloc ();
1003 }
1004
1005 //
1006 // always increase the use count!
1007 //
1008 mTlsIndexUseCount++;
1009
1010 //
1011 // Register to be notified on exit boot services so we can destroy the window.
1012 //
1013 Status = gBS->CreateEventEx (
1014 EVT_NOTIFY_SIGNAL,
1015 TPL_CALLBACK,
1016 KillNtGopThread,
1017 Private,
1018 &gEfiEventExitBootServicesGuid,
1019 &mGopScreenExitBootServicesEvent
1020 );
1021
1022 Private->ThreadInited = Private->WinNtThunk->CreateSemaphore (NULL, 0, 1, NULL);
1023 Private->ThreadHandle = Private->WinNtThunk->CreateThread (
1024 NULL,
1025 0,
1026 WinNtGopThreadWinMain,
1027 (VOID *) Private,
1028 0,
1029 &NewThreadId
1030 );
1031
1032 //
1033 // The other thread has entered the windows message loop so we can
1034 // continue our initialization.
1035 //
1036 Private->WinNtThunk->WaitForSingleObject (Private->ThreadInited, INFINITE);
1037 Private->WinNtThunk->CloseHandle (Private->ThreadInited);
1038
1039 return Status;
1040 }
1041
1042
1043 /**
1044
1045
1046 @return None
1047
1048 **/
1049 // TODO: Private - add argument and description to function comment
1050 // TODO: EFI_SUCCESS - add return value to function comment
1051 EFI_STATUS
WinNtGopConstructor(GOP_PRIVATE_DATA * Private)1052 WinNtGopConstructor (
1053 GOP_PRIVATE_DATA *Private
1054 )
1055 {
1056 Private->ModeData = mGopModeData;
1057
1058 Private->GraphicsOutput.QueryMode = WinNtGopQuerytMode;
1059 Private->GraphicsOutput.SetMode = WinNtGopSetMode;
1060 Private->GraphicsOutput.Blt = WinNtGopBlt;
1061
1062 //
1063 // Allocate buffer for Graphics Output Protocol mode information
1064 //
1065 Private->GraphicsOutput.Mode = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE));
1066 if (Private->GraphicsOutput.Mode == NULL) {
1067 return EFI_OUT_OF_RESOURCES;
1068 }
1069 Private->GraphicsOutput.Mode->Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
1070 if (Private->GraphicsOutput.Mode->Info == NULL) {
1071 return EFI_OUT_OF_RESOURCES;
1072 }
1073
1074 Private->GraphicsOutput.Mode->MaxMode = sizeof(mGopModeData) / sizeof(GOP_MODE_DATA);
1075 //
1076 // Till now, we have no idea about the window size.
1077 //
1078 Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1079 Private->GraphicsOutput.Mode->Info->Version = 0;
1080 Private->GraphicsOutput.Mode->Info->HorizontalResolution = 0;
1081 Private->GraphicsOutput.Mode->Info->VerticalResolution = 0;
1082 Private->GraphicsOutput.Mode->Info->PixelFormat = PixelBltOnly;
1083 Private->GraphicsOutput.Mode->SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1084 Private->GraphicsOutput.Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) NULL;
1085 Private->GraphicsOutput.Mode->FrameBufferSize = 0;
1086
1087 Private->HardwareNeedsStarting = TRUE;
1088 Private->FillLine = NULL;
1089
1090 WinNtGopInitializeSimpleTextInForWindow (Private);
1091
1092 return EFI_SUCCESS;
1093 }
1094
1095
1096 /**
1097
1098
1099 @return None
1100
1101 **/
1102 // TODO: Private - add argument and description to function comment
1103 // TODO: EFI_SUCCESS - add return value to function comment
1104 EFI_STATUS
WinNtGopDestructor(GOP_PRIVATE_DATA * Private)1105 WinNtGopDestructor (
1106 GOP_PRIVATE_DATA *Private
1107 )
1108 {
1109 if (!Private->HardwareNeedsStarting) {
1110 //
1111 // BugBug: Shutdown GOP Hardware and any child devices.
1112 //
1113 Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);
1114 Private->WinNtThunk->CloseHandle (Private->ThreadHandle);
1115
1116 mTlsIndexUseCount--;
1117
1118 //
1119 // The callback function for another window could still be called,
1120 // so we need to make sure there are no more users of mTlsIndex.
1121 //
1122 if (0 == mTlsIndexUseCount) {
1123 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);
1124
1125 Private->WinNtThunk->TlsFree (mTlsIndex);
1126 mTlsIndex = TLS_OUT_OF_INDEXES;
1127
1128 Private->WinNtThunk->UnregisterClass (
1129 Private->WindowsClass.lpszClassName,
1130 Private->WindowsClass.hInstance
1131 );
1132 }
1133
1134 WinNtGopDestroySimpleTextInForWindow (Private);
1135 }
1136
1137 //
1138 // Free graphics output protocol occupied resource
1139 //
1140 if (Private->GraphicsOutput.Mode != NULL) {
1141 if (Private->GraphicsOutput.Mode->Info != NULL) {
1142 FreePool (Private->GraphicsOutput.Mode->Info);
1143 }
1144 FreePool (Private->GraphicsOutput.Mode);
1145 }
1146
1147 return EFI_SUCCESS;
1148 }
1149
1150
1151 /**
1152 This is the GOP screen's callback notification function for exit-boot-services.
1153 All we do here is call WinNtGopDestructor().
1154
1155 @param Event not used
1156 @param Context pointer to the Private structure.
1157
1158 @return None.
1159
1160 **/
1161 VOID
1162 EFIAPI
KillNtGopThread(IN EFI_EVENT Event,IN VOID * Context)1163 KillNtGopThread (
1164 IN EFI_EVENT Event,
1165 IN VOID *Context
1166 )
1167 {
1168 WinNtGopDestructor (Context);
1169 }
1170