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