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