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