]> git.proxmox.com Git - mirror_edk2.git/blame - Nt32Pkg/WinNtGopDxe/WinNtGopScreen.c
Replace references to RFC 3066 with RFC 4646.
[mirror_edk2.git] / Nt32Pkg / WinNtGopDxe / WinNtGopScreen.c
CommitLineData
c9fc89a3 1/** @file\r
2\r
c0aa5e09 3Copyright (c) 2006 - 2009, Intel Corporation\r
c9fc89a3 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
c9fc89a3 249 ModeData = &Private->ModeData[ModeNumber];\r
250 This->Mode->Mode = ModeNumber;\r
251 Private->GraphicsOutput.Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;\r
252 Private->GraphicsOutput.Mode->Info->VerticalResolution = ModeData->VerticalResolution;\r
253 Private->GraphicsOutput.Mode->Info->PixelsPerScanLine = ModeData->HorizontalResolution;\r
254\r
255 if (Private->HardwareNeedsStarting) {\r
256 Status = WinNtGopStartWindow (\r
257 Private,\r
258 ModeData->HorizontalResolution,\r
259 ModeData->VerticalResolution,\r
260 ModeData->ColorDepth,\r
261 ModeData->RefreshRate\r
262 );\r
263 if (EFI_ERROR (Status)) {\r
264 return EFI_DEVICE_ERROR;\r
265 }\r
266\r
267 Private->HardwareNeedsStarting = FALSE;\r
268 } else {\r
269 //\r
270 // Change the resolution and resize of the window\r
271 //\r
272\r
273 //\r
274 // Free the old buffer. We do not save the content of the old buffer since the\r
275 // screen is to be cleared anyway. Clearing the screen is required by the EFI spec.\r
276 // See UEFI spec -EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode()\r
277 //\r
278 Private->WinNtThunk->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
279\r
280 //\r
281 // Allocate DIB frame buffer directly from NT for performance enhancement\r
282 // This buffer is the virtual screen/frame buffer. This buffer is not the\r
283 // same a a frame buffer. The first row of this buffer will be the bottom\r
284 // line of the image. This is an artifact of the way we draw to the screen.\r
285 //\r
286 Size = ModeData->HorizontalResolution * ModeData->VerticalResolution * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);\r
287 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (\r
288 Private->WinNtThunk->GetProcessHeap (),\r
289 HEAP_ZERO_MEMORY,\r
290 Size\r
291 );\r
292\r
293 //\r
294 // Update the virtual screen info data structure\r
295 //\r
296 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);\r
297 Private->VirtualScreenInfo->bV4Width = ModeData->HorizontalResolution;\r
298 Private->VirtualScreenInfo->bV4Height = ModeData->VerticalResolution;\r
299 Private->VirtualScreenInfo->bV4Planes = 1;\r
300 Private->VirtualScreenInfo->bV4BitCount = 32;\r
301 //\r
302 // uncompressed\r
303 //\r
304 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;\r
305\r
306 //\r
307 // The rest of the allocated memory block is the virtual screen buffer\r
308 //\r
309 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);\r
310\r
311 //\r
312 // Use the AdjuctWindowRect fuction to calculate the real width and height\r
313 // of the new window including the border and caption\r
314 //\r
315 Rect.left = 0;\r
316 Rect.top = 0;\r
317 Rect.right = ModeData->HorizontalResolution;\r
318 Rect.bottom = ModeData->VerticalResolution;\r
319\r
320 Private->WinNtThunk->AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);\r
321\r
322 Width = Rect.right - Rect.left;\r
323 Height = Rect.bottom - Rect.top;\r
324\r
325 //\r
326 // Retrieve the original window position information\r
327 //\r
328 Private->WinNtThunk->GetWindowRect (Private->WindowHandle, &Rect);\r
329\r
330 //\r
331 // Adjust the window size\r
332 //\r
333 Private->WinNtThunk->MoveWindow (Private->WindowHandle, Rect.left, Rect.top, Width, Height, TRUE);\r
334\r
335 }\r
336\r
337 NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * ModeData->HorizontalResolution);\r
338 if (NewFillLine == NULL) {\r
339 return EFI_DEVICE_ERROR;\r
340 }\r
341\r
342 if (Private->FillLine != NULL) {\r
343 FreePool (Private->FillLine);\r
344 }\r
345\r
346 Private->FillLine = NewFillLine;\r
347\r
348 Fill.Red = 0x00;\r
349 Fill.Green = 0x00;\r
350 Fill.Blue = 0x00;\r
351 This->Blt (\r
352 This,\r
353 &Fill,\r
354 EfiBltVideoFill,\r
355 0,\r
356 0,\r
357 0,\r
358 0,\r
359 ModeData->HorizontalResolution,\r
360 ModeData->VerticalResolution,\r
361 ModeData->HorizontalResolution * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
362 );\r
363 return EFI_SUCCESS;\r
364}\r
365\r
366\r
367/**\r
368 Blt pixels from the rectangle (Width X Height) formed by the BltBuffer\r
369 onto the graphics screen starting a location (X, Y). (0, 0) is defined as\r
370 the upper left hand side of the screen. (X, Y) can be outside of the\r
371 current screen geometry and the BltBuffer will be cliped when it is\r
372 displayed. X and Y can be negative or positive. If Width or Height is\r
373 bigger than the current video screen the image will be clipped.\r
374\r
375 @param This Protocol instance pointer.\r
376 @param X X location on graphics screen.\r
377 @param Y Y location on the graphics screen.\r
378 @param Width Width of BltBuffer.\r
379 @param Height Hight of BltBuffer\r
380 @param BltOperation Operation to perform on BltBuffer and video memory\r
381 @param BltBuffer Buffer containing data to blt into video buffer.\r
382 This buffer has a size of\r
383 Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
384 @param SourceX If the BltOperation is a EfiCopyBlt this is the\r
385 source of the copy. For other BLT operations this\r
386 argument is not used.\r
387 @param SourceX If the BltOperation is a EfiCopyBlt this is the\r
388 source of the copy. For other BLT operations this\r
389 argument is not used.\r
390\r
391 @retval EFI_SUCCESS The palette is updated with PaletteArray.\r
392 @retval EFI_INVALID_PARAMETER BltOperation is not valid.\r
393 @retval EFI_DEVICE_ERROR A hardware error occured writting to the video\r
394 buffer.\r
395\r
396**/\r
397// TODO: SourceY - add argument and description to function comment\r
398// TODO: DestinationX - add argument and description to function comment\r
399// TODO: DestinationY - add argument and description to function comment\r
400// TODO: Delta - add argument and description to function comment\r
401EFI_STATUS\r
402EFIAPI\r
403WinNtGopBlt (\r
404 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,\r
405 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL\r
406 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,\r
407 IN UINTN SourceX,\r
408 IN UINTN SourceY,\r
409 IN UINTN DestinationX,\r
410 IN UINTN DestinationY,\r
411 IN UINTN Width,\r
412 IN UINTN Height,\r
413 IN UINTN Delta OPTIONAL\r
414 )\r
415{\r
416 GOP_PRIVATE_DATA *Private;\r
417 EFI_TPL OriginalTPL;\r
418 UINTN DstY;\r
419 UINTN SrcY;\r
420 RGBQUAD *VScreen;\r
421 RGBQUAD *VScreenSrc;\r
422 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
423 UINTN Index;\r
424 RECT Rect;\r
425 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;\r
426 UINT32 VerticalResolution;\r
427 UINT32 HorizontalResolution;\r
428\r
429 Private = GOP_PRIVATE_DATA_FROM_THIS (This);\r
430\r
431 if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {\r
432 return EFI_INVALID_PARAMETER;\r
433 }\r
434\r
435 if (Width == 0 || Height == 0) {\r
436 return EFI_INVALID_PARAMETER;\r
437 }\r
438 //\r
439 // If Delta is zero, then the entire BltBuffer is being used, so Delta\r
440 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,\r
441 // the number of bytes in each row can be computed.\r
442 //\r
443 if (Delta == 0) {\r
444 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);\r
445 }\r
446\r
447 //\r
448 // We need to fill the Virtual Screen buffer with the blt data.\r
449 // The virtual screen is upside down, as the first row is the bootom row of\r
450 // the image.\r
451 //\r
452 VerticalResolution = This->Mode->Info->VerticalResolution;\r
453 HorizontalResolution = This->Mode->Info->HorizontalResolution;\r
454 if (BltOperation == EfiBltVideoToBltBuffer) {\r
455\r
456 //\r
457 // Video to BltBuffer: Source is Video, destination is BltBuffer\r
458 //\r
459 if (SourceY + Height > VerticalResolution) {\r
460 return EFI_INVALID_PARAMETER;\r
461 }\r
462\r
463 if (SourceX + Width > HorizontalResolution) {\r
464 return EFI_INVALID_PARAMETER;\r
465 }\r
466 //\r
467 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
468 // We would not want a timer based event (Cursor, ...) to come in while we are\r
469 // doing this operation.\r
470 //\r
471 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
472\r
473 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {\r
474 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
475 VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX];\r
476 CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Width);\r
477 }\r
478 } else {\r
479 //\r
480 // BltBuffer to Video: Source is BltBuffer, destination is Video\r
481 //\r
482 if (DestinationY + Height > VerticalResolution) {\r
483 return EFI_INVALID_PARAMETER;\r
484 }\r
485\r
486 if (DestinationX + Width > HorizontalResolution) {\r
487 return EFI_INVALID_PARAMETER;\r
488 }\r
489\r
490 //\r
491 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.\r
492 // We would not want a timer based event (Cursor, ...) to come in while we are\r
493 // doing this operation.\r
494 //\r
495 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
496\r
497 if (BltOperation == EfiBltVideoFill) {\r
498 FillPixel = BltBuffer;\r
499 for (Index = 0; Index < Width; Index++) {\r
500 Private->FillLine[Index] = *FillPixel;\r
501 }\r
502 }\r
503\r
504 for (Index = 0; Index < Height; Index++) {\r
505 if (DestinationY <= SourceY) {\r
506 SrcY = SourceY + Index;\r
507 DstY = DestinationY + Index;\r
508 } else {\r
509 SrcY = SourceY + Height - Index - 1;\r
510 DstY = DestinationY + Height - Index - 1;\r
511 }\r
512\r
513 VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + DestinationX];\r
514 switch (BltOperation) {\r
515 case EfiBltBufferToVideo:\r
516 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Delta) + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
517 CopyMem (VScreen, Blt, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
518 break;\r
519\r
520 case EfiBltVideoToVideo:\r
521 VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + SourceX];\r
522 CopyMem (VScreen, VScreenSrc, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
523 break;\r
524\r
525 case EfiBltVideoFill:\r
526 CopyMem (VScreen, Private->FillLine, Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
527 break;\r
528 }\r
529 }\r
530 }\r
531\r
532 if (BltOperation != EfiBltVideoToBltBuffer) {\r
533 //\r
534 // Mark the area we just blted as Invalid so WM_PAINT will update.\r
535 //\r
536 Rect.left = DestinationX;\r
537 Rect.top = DestinationY;\r
538 Rect.right = DestinationX + Width;\r
539 Rect.bottom = DestinationY + Height;\r
540 Private->WinNtThunk->InvalidateRect (Private->WindowHandle, &Rect, FALSE);\r
541\r
542 //\r
543 // Send the WM_PAINT message to the thread that is drawing the window. We\r
544 // are in the main thread and the window drawing is in a child thread.\r
545 // There is a child thread per window. We have no CriticalSection or Mutex\r
546 // since we write the data and the other thread displays the data. While\r
547 // we may miss some data for a short period of time this is no different than\r
548 // a write combining on writes to a frame buffer.\r
549 //\r
550\r
551 Private->WinNtThunk->UpdateWindow (Private->WindowHandle);\r
552 }\r
553\r
554 gBS->RestoreTPL (OriginalTPL);\r
555\r
556 return EFI_SUCCESS;\r
557}\r
558\r
559//\r
560// Construction and Destruction functions\r
561//\r
562\r
563\r
564/**\r
565\r
566\r
567 @return None\r
568\r
569**/\r
570// TODO: WinNtIo - add argument and description to function comment\r
571// TODO: EFI_UNSUPPORTED - add return value to function comment\r
572// TODO: EFI_SUCCESS - add return value to function comment\r
573EFI_STATUS\r
574WinNtGopSupported (\r
575 IN EFI_WIN_NT_IO_PROTOCOL *WinNtIo\r
576 )\r
577{\r
578 //\r
579 // Check to see if the IO abstraction represents a device type we support.\r
580 //\r
581 // This would be replaced a check of PCI subsystem ID, etc.\r
582 //\r
583 if (!CompareGuid (WinNtIo->TypeGuid, &gEfiWinNtGopGuid)) {\r
584 return EFI_UNSUPPORTED;\r
585 }\r
586\r
587 return EFI_SUCCESS;\r
588}\r
589\r
590\r
591/**\r
592 Win32 Windows event handler.\r
593\r
594 See Win32 Book\r
595\r
596 @return See Win32 Book\r
597\r
598**/\r
599// TODO: hwnd - add argument and description to function comment\r
600// TODO: iMsg - add argument and description to function comment\r
601// TODO: wParam - add argument and description to function comment\r
602// TODO: lParam - add argument and description to function comment\r
603LRESULT\r
604CALLBACK\r
605WinNtGopThreadWindowProc (\r
606 IN HWND hwnd,\r
607 IN UINT iMsg,\r
608 IN WPARAM wParam,\r
609 IN LPARAM lParam\r
610 )\r
611{\r
612 GOP_PRIVATE_DATA *Private;\r
613 UINTN Size;\r
614 HDC Handle;\r
615 PAINTSTRUCT PaintStruct;\r
616 LPARAM Index;\r
617 EFI_INPUT_KEY Key;\r
618\r
619 //\r
620 // BugBug - if there are two instances of this DLL in memory (such as is\r
621 // the case for ERM), the correct instance of this function may not be called.\r
622 // This also means that the address of the mTlsIndex value will be wrong, and\r
623 // the value may be wrong too.\r
624 //\r
625\r
626\r
627 //\r
628 // Use mTlsIndex global to get a Thread Local Storage version of Private.\r
629 // This works since each Gop protocol has a unique Private data instance and\r
630 // a unique thread.\r
631 //\r
632 Private = mWinNt->TlsGetValue (mTlsIndex);\r
633 ASSERT (NULL != Private);\r
634\r
635 switch (iMsg) {\r
636 case WM_CREATE:\r
637 Size = Private->GraphicsOutput.Mode->Info->HorizontalResolution * Private->GraphicsOutput.Mode->Info->VerticalResolution * sizeof (RGBQUAD);\r
638\r
639 //\r
640 // Allocate DIB frame buffer directly from NT for performance enhancement\r
641 // This buffer is the virtual screen/frame buffer. This buffer is not the\r
642 // same a a frame buffer. The first fow of this buffer will be the bottom\r
643 // line of the image. This is an artifact of the way we draw to the screen.\r
644 //\r
645 Private->VirtualScreenInfo = Private->WinNtThunk->HeapAlloc (\r
646 Private->WinNtThunk->GetProcessHeap (),\r
647 HEAP_ZERO_MEMORY,\r
648 Size\r
649 );\r
650\r
651 Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);\r
652 Private->VirtualScreenInfo->bV4Width = Private->GraphicsOutput.Mode->Info->HorizontalResolution;\r
653 Private->VirtualScreenInfo->bV4Height = Private->GraphicsOutput.Mode->Info->VerticalResolution;\r
654 Private->VirtualScreenInfo->bV4Planes = 1;\r
655 Private->VirtualScreenInfo->bV4BitCount = 32;\r
656 //\r
657 // uncompressed\r
658 //\r
659 Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;\r
660 Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);\r
661 return 0;\r
662\r
663 case WM_PAINT:\r
664 //\r
665 // I have not found a way to convert hwnd into a Private context. So for\r
666 // now we use this API to convert hwnd to Private data.\r
667 //\r
668\r
669 Handle = mWinNt->BeginPaint (hwnd, &PaintStruct);\r
670\r
671 mWinNt->SetDIBitsToDevice (\r
672 Handle, // Destination Device Context\r
673 0, // Destination X - 0\r
674 0, // Destination Y - 0\r
675 Private->GraphicsOutput.Mode->Info->HorizontalResolution, // Width\r
676 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Height\r
677 0, // Source X\r
678 0, // Source Y\r
679 0, // DIB Start Scan Line\r
680 Private->GraphicsOutput.Mode->Info->VerticalResolution, // Number of scan lines\r
681 Private->VirtualScreen, // Address of array of DIB bits\r
682 (BITMAPINFO *) Private->VirtualScreenInfo, // Address of structure with bitmap info\r
683 DIB_RGB_COLORS // RGB or palette indexes\r
684 );\r
685\r
686 mWinNt->EndPaint (hwnd, &PaintStruct);\r
687 return 0;\r
688\r
689 //\r
690 // F10 and the ALT key do not create a WM_KEYDOWN message, thus this special case\r
62cf113f 691 // WM_SYSKEYDOWN is posted when F10 is pressed or \r
692 // holds down ALT key and then presses another key.\r
c9fc89a3 693 //\r
694 case WM_SYSKEYDOWN:\r
695 Key.ScanCode = 0;\r
696 switch (wParam) {\r
697 case VK_F10:\r
698 Key.ScanCode = SCAN_F10;\r
699 Key.UnicodeChar = 0;\r
700 GopPrivateAddQ (Private, Key);\r
701 return 0;\r
702 }\r
c9fc89a3 703\r
62cf113f 704 if ((lParam & GOP_ALT_KEY_PRESSED) == GOP_ALT_KEY_PRESSED) {\r
705 //\r
706 // ALT is pressed with another key pressed\r
707 //\r
708 WinNtGopConvertParamToEfiKey (Private, &wParam, &Key);\r
709\r
710 if ((lParam & GOP_EXTENDED_KEY) == GOP_EXTENDED_KEY) {\r
711 Private->RightAlt = TRUE;\r
712 } else {\r
713 Private->LeftAlt = TRUE;\r
714 }\r
715\r
716 if (Private->RightAlt && Private->LeftAlt) {\r
717 Private->LeftAlt = FALSE;\r
718 }\r
719 }\r
720\r
721 if (Key.ScanCode != 0) {\r
722 Key.UnicodeChar = 0;\r
723 GopPrivateAddQ (Private, Key);\r
724 }\r
725\r
726 return 0;\r
727\r
728 case WM_SYSKEYUP:\r
729 if ((lParam & GOP_ALT_KEY_PRESSED) == GOP_ALT_KEY_PRESSED) {\r
730 //\r
731 // ALT is pressed with another key released\r
732 //\r
733 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, FALSE); \r
734 //\r
735 // Actually ALT key is still held down here.\r
736 // Change the ALT key state when another key is released\r
737 // by user because we did not find a better solution to\r
738 // get a released ALT key. \r
739 //\r
740 Private->RightAlt = FALSE;\r
741 Private->LeftAlt = FALSE;\r
c9fc89a3 742 }\r
743\r
62cf113f 744 return 0;\r
745\r
746\r
747 case WM_KEYDOWN:\r
748 Key.ScanCode = 0;\r
749 WinNtGopConvertParamToEfiKey (Private, &wParam, &Key);\r
c9fc89a3 750 if (Key.ScanCode != 0) {\r
751 Key.UnicodeChar = 0;\r
752 GopPrivateAddQ (Private, Key);\r
753 }\r
754\r
755 return 0;\r
756\r
62cf113f 757 case WM_KEYUP:\r
758 WinNtGopConvertParamToEfiKeyShiftState (Private, &wParam, FALSE); \r
759 return 0;\r
760\r
c9fc89a3 761 case WM_CHAR:\r
762 //\r
763 // The ESC key also generate WM_CHAR.\r
764 //\r
765 if (wParam == 0x1B) {\r
766 return 0;\r
767 }\r
768\r
769 for (Index = 0; Index < (lParam & 0xffff); Index++) {\r
770 if (wParam != 0) {\r
771 Key.UnicodeChar = (CHAR16) wParam;\r
772 Key.ScanCode = 0;\r
773 GopPrivateAddQ (Private, Key);\r
774 }\r
775 }\r
776\r
777 return 0;\r
778\r
779 case WM_CLOSE:\r
780 //\r
781 // This close message is issued by user, core is not aware of this,\r
782 // so don't release the window display resource, just hide the window.\r
783 //\r
784 Private->WinNtThunk->ShowWindow (Private->WindowHandle, SW_HIDE);\r
785 return 0;\r
786\r
787 case WM_DESTROY:\r
788 mWinNt->DestroyWindow (hwnd);\r
789 mWinNt->PostQuitMessage (0);\r
790\r
791 mWinNt->HeapFree (Private->WinNtThunk->GetProcessHeap (), 0, Private->VirtualScreenInfo);\r
792\r
793 mWinNt->ExitThread (0);\r
794 return 0;\r
795\r
796 default:\r
797 break;\r
798 };\r
799\r
800 return mWinNt->DefWindowProc (hwnd, iMsg, wParam, lParam);\r
801}\r
802\r
803\r
804/**\r
805 This thread simulates the end of WinMain () aplication. Each Winow nededs\r
806 to process it's events. The messages are dispatched to\r
807 WinNtGopThreadWindowProc ().\r
808 Be very careful sine WinNtGopThreadWinMain () and WinNtGopThreadWindowProc ()\r
809 are running in a seperate thread. We have to do this to process the events.\r
810\r
811 @param lpParameter Handle of window to manage.\r
812\r
813 @return if a WM_QUIT message is returned exit.\r
814\r
815**/\r
816DWORD\r
817WINAPI\r
818WinNtGopThreadWinMain (\r
819 LPVOID lpParameter\r
820 )\r
821{\r
822 MSG Message;\r
823 GOP_PRIVATE_DATA *Private;\r
824 ATOM Atom;\r
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
860 Atom = Private->WinNtThunk->RegisterClassEx (&Private->WindowsClass);\r
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
885 &Private\r
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
1053 UINT32 UnregisterReturn;\r
1054\r
1055 if (!Private->HardwareNeedsStarting) {\r
1056 //\r
1057 // BugBug: Shutdown GOP Hardware and any child devices.\r
1058 //\r
1059 Private->WinNtThunk->SendMessage (Private->WindowHandle, WM_DESTROY, 0, 0);\r
1060 Private->WinNtThunk->CloseHandle (Private->ThreadHandle);\r
1061\r
1062 mTlsIndexUseCount--;\r
1063\r
1064 //\r
1065 // The callback function for another window could still be called,\r
1066 // so we need to make sure there are no more users of mTlsIndex.\r
1067 //\r
1068 if (0 == mTlsIndexUseCount) {\r
1069 ASSERT (TLS_OUT_OF_INDEXES != mTlsIndex);\r
1070\r
1071 Private->WinNtThunk->TlsFree (mTlsIndex);\r
1072 mTlsIndex = TLS_OUT_OF_INDEXES;\r
1073\r
1074 UnregisterReturn = Private->WinNtThunk->UnregisterClass (\r
1075 Private->WindowsClass.lpszClassName,\r
1076 Private->WindowsClass.hInstance\r
1077 );\r
1078 }\r
1079\r
1080 WinNtGopDestroySimpleTextInForWindow (Private);\r
1081 }\r
1082\r
1083 //\r
1084 // Free graphics output protocol occupied resource\r
1085 //\r
1086 if (Private->GraphicsOutput.Mode != NULL) {\r
1087 if (Private->GraphicsOutput.Mode->Info != NULL) {\r
1088 FreePool (Private->GraphicsOutput.Mode->Info);\r
1089 }\r
1090 FreePool (Private->GraphicsOutput.Mode);\r
1091 }\r
1092\r
1093 return EFI_SUCCESS;\r
1094}\r
1095\r
1096\r
1097/**\r
1098 This is the GOP screen's callback notification function for exit-boot-services.\r
1099 All we do here is call WinNtGopDestructor().\r
1100\r
1101 @param Event not used\r
1102 @param Context pointer to the Private structure.\r
1103\r
1104 @return None.\r
1105\r
1106**/\r
c9fc89a3 1107VOID\r
1108EFIAPI\r
1109KillNtGopThread (\r
1110 IN EFI_EVENT Event,\r
1111 IN VOID *Context\r
1112 )\r
1113{\r
1114 EFI_STATUS Status;\r
1115 Status = WinNtGopDestructor (Context);\r
1116}\r