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