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