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