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