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