1 /** @file
2   VGA Class Driver that managers VGA devices and produces Simple Text Output Protocol.
3 
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "VgaClass.h"
10 
11 //
12 // EFI Driver Binding Protocol for the VGA Class Driver
13 //
14 EFI_DRIVER_BINDING_PROTOCOL gVgaClassDriverBinding = {
15   VgaClassDriverBindingSupported,
16   VgaClassDriverBindingStart,
17   VgaClassDriverBindingStop,
18   0xa,
19   NULL,
20   NULL
21 };
22 
23 //
24 // Local variables
25 //
26 CHAR16               CrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
27 
28 //
29 // This list is used to define the valid extend chars.
30 // It also provides a mapping from Unicode to PCANSI or
31 // ASCII. The ASCII mapping we just made up.
32 //
33 //
34 UNICODE_TO_CHAR  UnicodeToPcAnsiOrAscii[] = {
35   {
36     BOXDRAW_HORIZONTAL,
37     0xc4,
38     L'-'
39   },
40   {
41     BOXDRAW_VERTICAL,
42     0xb3,
43     L'|'
44   },
45   {
46     BOXDRAW_DOWN_RIGHT,
47     0xda,
48     L'/'
49   },
50   {
51     BOXDRAW_DOWN_LEFT,
52     0xbf,
53     L'\\'
54   },
55   {
56     BOXDRAW_UP_RIGHT,
57     0xc0,
58     L'\\'
59   },
60   {
61     BOXDRAW_UP_LEFT,
62     0xd9,
63     L'/'
64   },
65   {
66     BOXDRAW_VERTICAL_RIGHT,
67     0xc3,
68     L'|'
69   },
70   {
71     BOXDRAW_VERTICAL_LEFT,
72     0xb4,
73     L'|'
74   },
75   {
76     BOXDRAW_DOWN_HORIZONTAL,
77     0xc2,
78     L'+'
79   },
80   {
81     BOXDRAW_UP_HORIZONTAL,
82     0xc1,
83     L'+'
84   },
85   {
86     BOXDRAW_VERTICAL_HORIZONTAL,
87     0xc5,
88     L'+'
89   },
90   {
91     BOXDRAW_DOUBLE_HORIZONTAL,
92     0xcd,
93     L'-'
94   },
95   {
96     BOXDRAW_DOUBLE_VERTICAL,
97     0xba,
98     L'|'
99   },
100   {
101     BOXDRAW_DOWN_RIGHT_DOUBLE,
102     0xd5,
103     L'/'
104   },
105   {
106     BOXDRAW_DOWN_DOUBLE_RIGHT,
107     0xd6,
108     L'/'
109   },
110   {
111     BOXDRAW_DOUBLE_DOWN_RIGHT,
112     0xc9,
113     L'/'
114   },
115   {
116     BOXDRAW_DOWN_LEFT_DOUBLE,
117     0xb8,
118     L'\\'
119   },
120   {
121     BOXDRAW_DOWN_DOUBLE_LEFT,
122     0xb7,
123     L'\\'
124   },
125   {
126     BOXDRAW_DOUBLE_DOWN_LEFT,
127     0xbb,
128     L'\\'
129   },
130   {
131     BOXDRAW_UP_RIGHT_DOUBLE,
132     0xd4,
133     L'\\'
134   },
135   {
136     BOXDRAW_UP_DOUBLE_RIGHT,
137     0xd3,
138     L'\\'
139   },
140   {
141     BOXDRAW_DOUBLE_UP_RIGHT,
142     0xc8,
143     L'\\'
144   },
145   {
146     BOXDRAW_UP_LEFT_DOUBLE,
147     0xbe,
148     L'/'
149   },
150   {
151     BOXDRAW_UP_DOUBLE_LEFT,
152     0xbd,
153     L'/'
154   },
155   {
156     BOXDRAW_DOUBLE_UP_LEFT,
157     0xbc,
158     L'/'
159   },
160   {
161     BOXDRAW_VERTICAL_RIGHT_DOUBLE,
162     0xc6,
163     L'|'
164   },
165   {
166     BOXDRAW_VERTICAL_DOUBLE_RIGHT,
167     0xc7,
168     L'|'
169   },
170   {
171     BOXDRAW_DOUBLE_VERTICAL_RIGHT,
172     0xcc,
173     L'|'
174   },
175   {
176     BOXDRAW_VERTICAL_LEFT_DOUBLE,
177     0xb5,
178     L'|'
179   },
180   {
181     BOXDRAW_VERTICAL_DOUBLE_LEFT,
182     0xb6,
183     L'|'
184   },
185   {
186     BOXDRAW_DOUBLE_VERTICAL_LEFT,
187     0xb9,
188     L'|'
189   },
190   {
191     BOXDRAW_DOWN_HORIZONTAL_DOUBLE,
192     0xd1,
193     L'+'
194   },
195   {
196     BOXDRAW_DOWN_DOUBLE_HORIZONTAL,
197     0xd2,
198     L'+'
199   },
200   {
201     BOXDRAW_DOUBLE_DOWN_HORIZONTAL,
202     0xcb,
203     L'+'
204   },
205   {
206     BOXDRAW_UP_HORIZONTAL_DOUBLE,
207     0xcf,
208     L'+'
209   },
210   {
211     BOXDRAW_UP_DOUBLE_HORIZONTAL,
212     0xd0,
213     L'+'
214   },
215   {
216     BOXDRAW_DOUBLE_UP_HORIZONTAL,
217     0xca,
218     L'+'
219   },
220   {
221     BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE,
222     0xd8,
223     L'+'
224   },
225   {
226     BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL,
227     0xd7,
228     L'+'
229   },
230   {
231     BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL,
232     0xce,
233     L'+'
234   },
235 
236   {
237     BLOCKELEMENT_FULL_BLOCK,
238     0xdb,
239     L'*'
240   },
241   {
242     BLOCKELEMENT_LIGHT_SHADE,
243     0xb0,
244     L'+'
245   },
246 
247   {
248     GEOMETRICSHAPE_UP_TRIANGLE,
249     0x1e,
250     L'^'
251   },
252   {
253     GEOMETRICSHAPE_RIGHT_TRIANGLE,
254     0x10,
255     L'>'
256   },
257   {
258     GEOMETRICSHAPE_DOWN_TRIANGLE,
259     0x1f,
260     L'v'
261   },
262   {
263     GEOMETRICSHAPE_LEFT_TRIANGLE,
264     0x11,
265     L'<'
266   },
267 
268   {
269     ARROW_LEFT,
270     0x3c,
271     L'<'
272   },
273 
274   {
275     ARROW_UP,
276     0x18,
277     L'^'
278   },
279 
280   {
281     ARROW_RIGHT,
282     0x3e,
283     L'>'
284   },
285 
286   {
287     ARROW_DOWN,
288     0x19,
289     L'v'
290   },
291 
292   {
293     0x0000,
294     0x00,
295     0x00
296   }
297 };
298 
299 /**
300   Entrypoint of this VGA Class Driver.
301 
302   This function is the entrypoint of this VGA Class Driver. It installs Driver Binding
303   Protocols together with Component Name Protocols.
304 
305   @param  ImageHandle       The firmware allocated handle for the EFI image.
306   @param  SystemTable       A pointer to the EFI System Table.
307 
308   @retval EFI_SUCCESS       The entry point is executed successfully.
309 
310 **/
311 EFI_STATUS
312 EFIAPI
InitializeVgaClass(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)313 InitializeVgaClass(
314   IN EFI_HANDLE           ImageHandle,
315   IN EFI_SYSTEM_TABLE     *SystemTable
316   )
317 {
318   EFI_STATUS              Status;
319 
320   //
321   // Install driver model protocol(s).
322   //
323   Status = EfiLibInstallDriverBindingComponentName2 (
324              ImageHandle,
325              SystemTable,
326              &gVgaClassDriverBinding,
327              ImageHandle,
328              &gVgaClassComponentName,
329              &gVgaClassComponentName2
330              );
331   ASSERT_EFI_ERROR (Status);
332 
333   return EFI_SUCCESS;
334 }
335 
336 /**
337   Internal worker function to program CRTC register via PCI I/O Protocol.
338 
339   @param VgaClassDev  device instance object
340   @param Address      Address of register to write
341   @param Data         Data to write to register.
342 
343 **/
344 VOID
WriteCrtc(IN VGA_CLASS_DEV * VgaClassDev,IN UINT16 Address,IN UINT8 Data)345 WriteCrtc (
346   IN  VGA_CLASS_DEV  *VgaClassDev,
347   IN  UINT16         Address,
348   IN  UINT8          Data
349   )
350 {
351   VgaClassDev->PciIo->Io.Write (
352                            VgaClassDev->PciIo,
353                            EfiPciIoWidthUint8,
354                            VgaClassDev->VgaMiniPort->CrtcAddressRegisterBar,
355                            VgaClassDev->VgaMiniPort->CrtcAddressRegisterOffset,
356                            1,
357                            &Address
358                            );
359 
360   VgaClassDev->PciIo->Io.Write (
361                            VgaClassDev->PciIo,
362                            EfiPciIoWidthUint8,
363                            VgaClassDev->VgaMiniPort->CrtcDataRegisterBar,
364                            VgaClassDev->VgaMiniPort->CrtcDataRegisterOffset,
365                            1,
366                            &Data
367                            );
368 }
369 
370 /**
371   Internal worker function to set cursor's position to VgaClass device
372 
373   @param  VgaClassDev   Private data structure for device instance.
374   @param  Column        Colomn of position to set cursor to.
375   @param  Row           Row of position to set cursor to.
376   @param  MaxColumn     Max value of column.
377 
378 **/
379 VOID
SetVideoCursorPosition(IN VGA_CLASS_DEV * VgaClassDev,IN UINTN Column,IN UINTN Row,IN UINTN MaxColumn)380 SetVideoCursorPosition (
381   IN  VGA_CLASS_DEV  *VgaClassDev,
382   IN  UINTN          Column,
383   IN  UINTN          Row,
384   IN  UINTN          MaxColumn
385   )
386 {
387   Column    = Column & 0xff;
388   Row       = Row & 0xff;
389   MaxColumn = MaxColumn & 0xff;
390 
391   WriteCrtc (
392     VgaClassDev,
393     CRTC_CURSOR_LOCATION_HIGH,
394     (UINT8) ((Row * MaxColumn + Column) >> 8)
395     );
396   WriteCrtc (
397     VgaClassDev,
398     CRTC_CURSOR_LOCATION_LOW,
399     (UINT8) ((Row * MaxColumn + Column) & 0xff)
400     );
401 }
402 
403 /**
404   Internal worker function to detect if a Unicode char is for Box Drawing text graphics.
405 
406   @param  Graphic  Unicode char to test.
407   @param  PcAnsi   Pointer to PCANSI equivalent of Graphic for output.
408                    If NULL, then PCANSI value is not returned.
409   @param  Ascii    Pointer to ASCII equivalent of Graphic for output.
410                    If NULL, then ASCII value is not returned.
411 
412   @retval TRUE     Gpaphic is a supported Unicode Box Drawing character.
413   @retval FALSE    Gpaphic is not a supported Unicode Box Drawing character.
414 
415 **/
416 BOOLEAN
LibIsValidTextGraphics(IN CHAR16 Graphic,OUT CHAR8 * PcAnsi,OPTIONAL OUT CHAR8 * Ascii OPTIONAL)417 LibIsValidTextGraphics (
418   IN  CHAR16  Graphic,
419   OUT CHAR8   *PcAnsi, OPTIONAL
420   OUT CHAR8   *Ascii OPTIONAL
421   )
422 {
423   UNICODE_TO_CHAR *Table;
424 
425   //
426   // Unicode drawing code charts are all in the 0x25xx range, arrows are 0x21xx.
427   // So first filter out values not in these 2 ranges.
428   //
429   if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
430     return FALSE;
431   }
432 
433   //
434   // Search UnicodeToPcAnsiOrAscii table for matching entry.
435   //
436   for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) {
437     if (Graphic == Table->Unicode) {
438       if (PcAnsi != NULL) {
439         *PcAnsi = Table->PcAnsi;
440       }
441 
442       if (Ascii != NULL) {
443         *Ascii = Table->Ascii;
444       }
445 
446       return TRUE;
447     }
448   }
449 
450   //
451   // If value is not found in UnicodeToPcAnsiOrAscii table, then return FALSE.
452   //
453   return FALSE;
454 }
455 
456 /**
457   Internal worker function to check whether input value is an ASCII char.
458 
459   @param  Char     Character to check.
460 
461   @retval TRUE     Input value is an ASCII char.
462   @retval FALSE    Input value is not an ASCII char.
463 
464 **/
465 BOOLEAN
IsValidAscii(IN CHAR16 Char)466 IsValidAscii (
467   IN  CHAR16  Char
468   )
469 {
470   if ((Char >= 0x20) && (Char <= 0x7f)) {
471     return TRUE;
472   }
473 
474   return FALSE;
475 }
476 
477 /**
478   Internal worker function to check whether input value is a unicode control char.
479 
480   @param  Char    Character to check.
481 
482   @retval TRUE     Input value is a unicode control char.
483   @retval FALSE    Input value is not a unicode control char.
484 
485 **/
486 BOOLEAN
IsValidEfiCntlChar(IN CHAR16 Char)487 IsValidEfiCntlChar (
488   IN  CHAR16  Char
489   )
490 {
491   if (Char == CHAR_NULL || Char == CHAR_BACKSPACE || Char == CHAR_LINEFEED || Char == CHAR_CARRIAGE_RETURN) {
492     return TRUE;
493   }
494 
495   return FALSE;
496 }
497 
498 /**
499   Tests to see if this driver supports a given controller.
500 
501   This function implments EFI_DRIVER_BINDING_PROTOCOL.Supported().
502   It Checks if this driver supports the controller specified. Any Controller
503   with VgaMiniPort Protocol and Pci I/O protocol can be supported.
504 
505   @param  This                A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
506   @param  ControllerHandle    Handle of device to test
507   @param  RemainingDevicePath Optional parameter use to pick a specific child
508                               device to start.
509 
510   @retval EFI_SUCCESS         This driver supports this device.
511   @retval EFI_ALREADY_STARTED This driver is already running on this device.
512   @retval EFI_UNSUPPORTED     This driver does not support this device.
513 
514 **/
515 EFI_STATUS
516 EFIAPI
VgaClassDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)517 VgaClassDriverBindingSupported (
518   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
519   IN EFI_HANDLE                   Controller,
520   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
521   )
522 {
523   EFI_STATUS                  Status;
524 
525   //
526   // Checks if Abstraction(s) needed to perform the supported test
527   //
528   Status = gBS->OpenProtocol (
529                   Controller,
530                   &gEfiVgaMiniPortProtocolGuid,
531                   NULL,
532                   This->DriverBindingHandle,
533                   Controller,
534                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
535                   );
536   if (EFI_ERROR (Status)) {
537     return Status;
538   }
539   //
540   // Open the IO Abstraction(s) needed to perform the supported test
541   //
542   Status = gBS->OpenProtocol (
543                   Controller,
544                   &gEfiPciIoProtocolGuid,
545                   NULL,
546                   This->DriverBindingHandle,
547                   Controller,
548                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
549                   );
550   if (EFI_ERROR (Status)) {
551     return Status;
552   }
553 
554   return Status;
555 }
556 
557 /**
558   Starts the device controller.
559 
560   This function implments EFI_DRIVER_BINDING_PROTOCOL.Start().
561   It starts the device specified by Controller with the driver based on PCI I/O Protocol
562   and VgaMiniPort Protocol. It creates context for device instance and install EFI_SIMPLE_TEXT_OUT_PROTOCOL.
563 
564   @param  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
565   @param  ControllerHandle     Handle of device to bind driver to
566   @param  RemainingDevicePath  Optional parameter use to pick a specific child
567                                device to start.
568 
569   @retval EFI_SUCCESS          The device was started.
570   @retval other                Fail to start the device.
571 
572 **/
573 EFI_STATUS
574 EFIAPI
VgaClassDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)575 VgaClassDriverBindingStart (
576   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
577   IN EFI_HANDLE                   Controller,
578   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
579   )
580 {
581   EFI_STATUS                  Status;
582   EFI_VGA_MINI_PORT_PROTOCOL  *VgaMiniPort;
583   EFI_PCI_IO_PROTOCOL         *PciIo;
584   VGA_CLASS_DEV               *VgaClassPrivate;
585   EFI_DEVICE_PATH_PROTOCOL    *DevicePath;
586 
587   Status = gBS->HandleProtocol (
588                   Controller,
589                   &gEfiDevicePathProtocolGuid,
590                   (VOID **) &DevicePath
591                   );
592   if (EFI_ERROR (Status)) {
593     return Status;
594   }
595   //
596   // Report that VGA Class driver is being enabled
597   //
598   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
599     EFI_PROGRESS_CODE,
600     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
601     DevicePath
602     );
603 
604   //
605   // Open the PCI I/O Protocol
606   //
607   Status = gBS->OpenProtocol (
608                   Controller,
609                   &gEfiPciIoProtocolGuid,
610                   (VOID **) &PciIo,
611                   This->DriverBindingHandle,
612                   Controller,
613                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
614                   );
615   if (EFI_ERROR (Status)) {
616     return Status;
617   }
618   //
619   // Open the VGA Mini Port Protocol
620   //
621   Status = gBS->OpenProtocol (
622                   Controller,
623                   &gEfiVgaMiniPortProtocolGuid,
624                   (VOID **) &VgaMiniPort,
625                   This->DriverBindingHandle,
626                   Controller,
627                   EFI_OPEN_PROTOCOL_BY_DRIVER
628                   );
629   if (EFI_ERROR (Status)) {
630     return Status;
631   }
632   //
633   // Allocate the private device structure
634   //
635   VgaClassPrivate = AllocateZeroPool (sizeof (VGA_CLASS_DEV));
636   ASSERT (VgaClassPrivate != NULL);
637 
638   //
639   // Initialize the private device structure
640   //
641   VgaClassPrivate->Signature   = VGA_CLASS_DEV_SIGNATURE;
642   VgaClassPrivate->Handle      = Controller;
643   VgaClassPrivate->VgaMiniPort = VgaMiniPort;
644   VgaClassPrivate->PciIo       = PciIo;
645 
646   VgaClassPrivate->SimpleTextOut.Reset             = VgaClassReset;
647   VgaClassPrivate->SimpleTextOut.OutputString      = VgaClassOutputString;
648   VgaClassPrivate->SimpleTextOut.TestString        = VgaClassTestString;
649   VgaClassPrivate->SimpleTextOut.ClearScreen       = VgaClassClearScreen;
650   VgaClassPrivate->SimpleTextOut.SetAttribute      = VgaClassSetAttribute;
651   VgaClassPrivate->SimpleTextOut.SetCursorPosition = VgaClassSetCursorPosition;
652   VgaClassPrivate->SimpleTextOut.EnableCursor      = VgaClassEnableCursor;
653   VgaClassPrivate->SimpleTextOut.QueryMode         = VgaClassQueryMode;
654   VgaClassPrivate->SimpleTextOut.SetMode           = VgaClassSetMode;
655 
656   VgaClassPrivate->SimpleTextOut.Mode              = &VgaClassPrivate->SimpleTextOutputMode;
657   VgaClassPrivate->SimpleTextOutputMode.MaxMode    = VgaMiniPort->MaxMode;
658   VgaClassPrivate->DevicePath                      = DevicePath;
659 
660   //
661   // Initialize the VGA device.
662   //
663   Status = VgaClassPrivate->SimpleTextOut.SetAttribute (
664                                             &VgaClassPrivate->SimpleTextOut,
665                                             EFI_TEXT_ATTR (EFI_WHITE, EFI_BLACK)
666                                             );
667   if (EFI_ERROR (Status)) {
668     goto ErrorExit;
669   }
670 
671   Status = VgaClassPrivate->SimpleTextOut.Reset (
672                                             &VgaClassPrivate->SimpleTextOut,
673                                             FALSE
674                                             );
675   if (EFI_ERROR (Status)) {
676     goto ErrorExit;
677   }
678 
679   Status = VgaClassPrivate->SimpleTextOut.EnableCursor (
680                                             &VgaClassPrivate->SimpleTextOut,
681                                             TRUE
682                                             );
683   if (EFI_ERROR (Status)) {
684     goto ErrorExit;
685   }
686 
687   Status = gBS->InstallMultipleProtocolInterfaces (
688                   &Controller,
689                   &gEfiSimpleTextOutProtocolGuid,
690                   &VgaClassPrivate->SimpleTextOut,
691                   NULL
692                   );
693 
694   return Status;
695 
696 ErrorExit:
697   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
698     EFI_ERROR_CODE | EFI_ERROR_MINOR,
699     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
700     DevicePath
701     );
702 
703   return Status;
704 
705 }
706 
707 /**
708   Starts the device controller.
709 
710   This function implments EFI_DRIVER_BINDING_PROTOCOL.Stop().
711   It stops this driver on Controller. Support stopping any child handles
712   created by this driver.
713 
714   @param  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
715   @param  ControllerHandle  A handle to the device being stopped.
716   @param  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
717   @param  ChildHandleBuffer An array of child handles to be freed.
718 
719   @retval EFI_SUCCESS       This driver is removed ControllerHandle
720   @retval other             This driver was not removed from this device
721 
722 **/
723 EFI_STATUS
724 EFIAPI
VgaClassDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)725 VgaClassDriverBindingStop (
726   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
727   IN  EFI_HANDLE                      Controller,
728   IN  UINTN                           NumberOfChildren,
729   IN  EFI_HANDLE                      *ChildHandleBuffer OPTIONAL
730   )
731 {
732   EFI_STATUS                    Status;
733   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *SimpleTextOut;
734   VGA_CLASS_DEV                 *VgaClassPrivate;
735 
736   Status = gBS->OpenProtocol (
737                   Controller,
738                   &gEfiSimpleTextOutProtocolGuid,
739                   (VOID **) &SimpleTextOut,
740                   This->DriverBindingHandle,
741                   Controller,
742                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
743                   );
744   if (EFI_ERROR (Status)) {
745     return Status;
746   }
747 
748   VgaClassPrivate = VGA_CLASS_DEV_FROM_THIS (SimpleTextOut);
749 
750   //
751   // Report that VGA Class driver is being disabled
752   //
753   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
754     EFI_PROGRESS_CODE,
755     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
756     VgaClassPrivate->DevicePath
757     );
758 
759   Status = gBS->UninstallProtocolInterface (
760                   Controller,
761                   &gEfiSimpleTextOutProtocolGuid,
762                   &VgaClassPrivate->SimpleTextOut
763                   );
764   if (EFI_ERROR (Status)) {
765     return Status;
766   }
767   //
768   // Release PCI I/O and VGA Mini Port Protocols on the controller handle.
769   //
770   gBS->CloseProtocol (
771          Controller,
772          &gEfiPciIoProtocolGuid,
773          This->DriverBindingHandle,
774          Controller
775          );
776 
777   gBS->CloseProtocol (
778          Controller,
779          &gEfiVgaMiniPortProtocolGuid,
780          This->DriverBindingHandle,
781          Controller
782          );
783 
784   FreePool (VgaClassPrivate);
785 
786   return EFI_SUCCESS;
787 }
788 
789 /**
790   Resets the text output device hardware.
791 
792   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
793   It resets the text output device hardware. The cursor position is set to (0, 0),
794   and the screen is cleared to the default background color for the output device.
795 
796   @param  This                 Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
797   @param  ExtendedVerification Indicates that the driver may perform a more exhaustive
798                                verification operation of the device during reset.
799 
800   @retval EFI_SUCCESS          The text output device was reset.
801   @retval EFI_DEVICE_ERROR     The text output device is not functioning correctly and could not be reset.
802 
803 **/
804 EFI_STATUS
805 EFIAPI
VgaClassReset(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN ExtendedVerification)806 VgaClassReset (
807   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL     *This,
808   IN  BOOLEAN                             ExtendedVerification
809   )
810 {
811   EFI_STATUS    Status;
812   VGA_CLASS_DEV *VgaClassPrivate;
813 
814   VgaClassPrivate = VGA_CLASS_DEV_FROM_THIS (This);
815 
816   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
817     EFI_PROGRESS_CODE,
818     EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_RESET,
819     VgaClassPrivate->DevicePath
820     );
821 
822   This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));
823 
824   Status = This->SetMode (This, 0);
825   if (EFI_ERROR (Status)) {
826     return Status;
827   }
828 
829   return This->ClearScreen (This);
830 }
831 
832 /**
833   Writes a Unicode string to the output device.
834 
835   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
836   It writes a Unicode string to the output device. This is the most basic output mechanism
837   on an output device.
838 
839   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
840   @param  String                 The Null-terminated Unicode string to be displayed on the output device(s).
841 
842   @retval EFI_SUCCESS            The string was output to the device.
843   @retval EFI_DEVICE_ERROR       The device reported an error while attempting to output the text.
844   @retval EFI_UNSUPPORTED        The output device's mode is not currently in a defined text mode.
845   @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the characters in
846                                  the Unicode string could not be rendered and were skipped.
847 
848 **/
849 EFI_STATUS
850 EFIAPI
VgaClassOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * String)851 VgaClassOutputString (
852   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
853   IN  CHAR16                          *String
854   )
855 {
856   EFI_STATUS                  Status;
857   VGA_CLASS_DEV               *VgaClassDev;
858   EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
859   UINTN                       MaxColumn;
860   UINTN                       MaxRow;
861   UINT32                      VideoChar;
862   CHAR8                       GraphicChar;
863 
864   VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
865   Mode        = This->Mode;
866 
867   Status = This->QueryMode (
868                    This,
869                    Mode->Mode,
870                    &MaxColumn,
871                    &MaxRow
872                    );
873   if (EFI_ERROR (Status)) {
874     return Status;
875   }
876 
877   //
878   // Parse each character of the string to output
879   //
880   for (; *String != CHAR_NULL; String++) {
881 
882     switch (*String) {
883     case CHAR_BACKSPACE:
884       if (Mode->CursorColumn > 0) {
885         Mode->CursorColumn--;
886       }
887       break;
888 
889     case CHAR_LINEFEED:
890       if (Mode->CursorRow == (INT32) (MaxRow - 1)) {
891         //
892         // Scroll the screen by copying the contents
893         // of the VGA display up one line
894         //
895         VgaClassDev->PciIo->CopyMem (
896                               VgaClassDev->PciIo,
897                               EfiPciIoWidthUint32,
898                               VgaClassDev->VgaMiniPort->VgaMemoryBar,
899                               VgaClassDev->VgaMiniPort->VgaMemoryOffset,
900                               VgaClassDev->VgaMiniPort->VgaMemoryBar,
901                               VgaClassDev->VgaMiniPort->VgaMemoryOffset + MaxColumn * 2,
902                               ((MaxRow - 1) * MaxColumn) >> 1
903                               );
904 
905         //
906         // Print Blank Line of spaces with the current color attributes
907         //
908         VideoChar = (Mode->Attribute << 8) | ' ';
909         VideoChar = (VideoChar << 16) | VideoChar;
910         VgaClassDev->PciIo->Mem.Write (
911                                   VgaClassDev->PciIo,
912                                   EfiPciIoWidthFillUint32,
913                                   VgaClassDev->VgaMiniPort->VgaMemoryBar,
914                                   VgaClassDev->VgaMiniPort->VgaMemoryOffset + (MaxRow - 1) * MaxColumn * 2,
915                                   MaxColumn >> 1,
916                                   &VideoChar
917                                   );
918       }
919 
920       if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
921         Mode->CursorRow++;
922       }
923       break;
924 
925     case CHAR_CARRIAGE_RETURN:
926       Mode->CursorColumn = 0;
927       break;
928 
929     default:
930       if (!LibIsValidTextGraphics (*String, &GraphicChar, NULL)) {
931         //
932         // If this character is not ,Box Drawing text graphics, then convert it to ASCII.
933         //
934         GraphicChar = (CHAR8) *String;
935         if (!IsValidAscii (GraphicChar)) {
936           //
937           // If not valid ASCII char, convert it to "?"
938           //
939           GraphicChar = '?';
940         }
941       }
942 
943       VideoChar = (Mode->Attribute << 8) | GraphicChar;
944       VgaClassDev->PciIo->Mem.Write (
945                                 VgaClassDev->PciIo,
946                                 EfiPciIoWidthUint16,
947                                 VgaClassDev->VgaMiniPort->VgaMemoryBar,
948                                 VgaClassDev->VgaMiniPort->VgaMemoryOffset + ((Mode->CursorRow * MaxColumn + Mode->CursorColumn) * 2),
949                                 1,
950                                 &VideoChar
951                                 );
952 
953       if (Mode->CursorColumn >= (INT32) (MaxColumn - 1)) {
954         This->OutputString (This, CrLfString);
955       } else {
956         Mode->CursorColumn++;
957       }
958       break;
959     }
960   }
961 
962   SetVideoCursorPosition (
963     VgaClassDev,
964     (UINTN) Mode->CursorColumn,
965     (UINTN) Mode->CursorRow,
966     MaxColumn
967     );
968 
969   return EFI_SUCCESS;
970 }
971 
972 /**
973   Verifies that all characters in a Unicode string can be output to the target device.
974 
975   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
976   It verifies that all characters in a Unicode string can be output to the target device.
977 
978   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
979   @param  String                 The Null-terminated Unicode string to be examined for the output device(s).
980 
981   @retval EFI_SUCCESS            The device(s) are capable of rendering the output string.
982   @retval EFI_UNSUPPORTED        Some of the characters in the Unicode string cannot be rendered by
983                                  one or more of the output devices mapped by the EFI handle.
984 
985 **/
986 EFI_STATUS
987 EFIAPI
VgaClassTestString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN CHAR16 * String)988 VgaClassTestString (
989   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
990   IN  CHAR16                          *String
991   )
992 {
993   while (*String != CHAR_NULL) {
994     if (!(IsValidAscii (*String) || IsValidEfiCntlChar (*String) || LibIsValidTextGraphics (*String, NULL, NULL))) {
995       return EFI_UNSUPPORTED;
996     }
997 
998     String++;
999   }
1000 
1001   return EFI_SUCCESS;
1002 }
1003 
1004 /**
1005   Clears the output device(s) display to the currently selected background color.
1006 
1007   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
1008   The ClearScreen() function clears the output device(s) display to the currently
1009   selected background color. The cursor position is set to (0, 0).
1010 
1011   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1012 
1013   @retval EFI_SUCESS             The operation completed successfully.
1014   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request.
1015   @retval EFI_UNSUPPORTED        The output device is not in a valid text mode.
1016 
1017 **/
1018 EFI_STATUS
1019 EFIAPI
VgaClassClearScreen(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This)1020 VgaClassClearScreen (
1021   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *This
1022   )
1023 {
1024   EFI_STATUS    Status;
1025   VGA_CLASS_DEV *VgaClassDev;
1026   UINTN         MaxRow;
1027   UINTN         MaxColumn;
1028   UINT32        VideoChar;
1029 
1030   VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
1031 
1032   Status = This->QueryMode (
1033                    This,
1034                    This->Mode->Mode,
1035                    &MaxColumn,
1036                    &MaxRow
1037                    );
1038   if (EFI_ERROR (Status)) {
1039     return Status;
1040   }
1041 
1042   VideoChar = (This->Mode->Attribute << 8) | ' ';
1043   VideoChar = (VideoChar << 16) | VideoChar;
1044   VgaClassDev->PciIo->Mem.Write (
1045                             VgaClassDev->PciIo,
1046                             EfiPciIoWidthFillUint32,
1047                             VgaClassDev->VgaMiniPort->VgaMemoryBar,
1048                             VgaClassDev->VgaMiniPort->VgaMemoryOffset,
1049                             (MaxRow * MaxColumn) >> 1,
1050                             &VideoChar
1051                             );
1052 
1053   This->SetCursorPosition (This, 0, 0);
1054 
1055   return EFI_SUCCESS;
1056 }
1057 
1058 /**
1059   Sets the background and foreground colors for theOutputString() and ClearScreen() functions.
1060 
1061   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
1062   It sets the background and foreground colors for the OutputString() and ClearScreen() functions.
1063   The color mask can be set even when the device is in an invalid text mode.
1064   Devices supporting a different number of text colors are required to emulate the above colors
1065   to the best of the device's capabilities.
1066 
1067   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1068   @param  Attribute              The attribute to set.
1069                                  Bits 0..3 are the foreground color,
1070                                  and bits 4..6 are the background color.
1071 
1072   @retval EFI_SUCCESS            The requested attributes were set.
1073   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request.
1074 
1075 **/
1076 EFI_STATUS
1077 EFIAPI
VgaClassSetAttribute(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Attribute)1078 VgaClassSetAttribute (
1079   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1080   IN  UINTN                           Attribute
1081   )
1082 {
1083   if (Attribute <= EFI_MAX_ATTRIBUTE) {
1084     This->Mode->Attribute = (INT32) Attribute;
1085     return EFI_SUCCESS;
1086   }
1087 
1088   return EFI_UNSUPPORTED;
1089 }
1090 
1091 /**
1092   Sets the current coordinates of the cursor position.
1093 
1094   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
1095   It sets the current coordinates of the cursor position.
1096   The upper left corner of the screen is defined as coordinate (0, 0).
1097 
1098   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1099   @param  Column                 Column of position to set the cursor to.
1100   @param  Row                    Row of position to set the cursor to.
1101 
1102   @retval EFI_SUCCESS            The operation completed successfully.
1103   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request.
1104   @retval EFI_UNSUPPORTED        The output device is not in a valid text mode, or the cursor
1105                                  position is invalid for the current mode.
1106 
1107 **/
1108 EFI_STATUS
1109 EFIAPI
VgaClassSetCursorPosition(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN Column,IN UINTN Row)1110 VgaClassSetCursorPosition (
1111   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1112   IN  UINTN                           Column,
1113   IN  UINTN                           Row
1114   )
1115 {
1116   EFI_STATUS    Status;
1117   VGA_CLASS_DEV *VgaClassDev;
1118   UINTN         MaxColumn;
1119   UINTN         MaxRow;
1120 
1121   VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
1122 
1123   Status = This->QueryMode (
1124                    This,
1125                    This->Mode->Mode,
1126                    &MaxColumn,
1127                    &MaxRow
1128                    );
1129   if (EFI_ERROR (Status)) {
1130     return Status;
1131   }
1132 
1133   if (Column >= MaxColumn || Row >= MaxRow) {
1134     return EFI_UNSUPPORTED;
1135   }
1136 
1137   SetVideoCursorPosition (VgaClassDev, Column, Row, MaxColumn);
1138 
1139   This->Mode->CursorColumn  = (INT32) Column;
1140   This->Mode->CursorRow     = (INT32) Row;
1141 
1142   return EFI_SUCCESS;
1143 }
1144 
1145 /**
1146   Makes the cursor visible or invisible.
1147 
1148   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.EnableCursor().
1149   It makes the cursor visible or invisible.
1150 
1151   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1152   @param  Visible                If TRUE, the cursor is set to be visible.
1153                                  If FALSE, the cursor is set to be invisible.
1154 
1155   @retval EFI_SUCESS             The operation completed successfully.
1156   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request or the
1157                                  device does not support changing the cursor mode.
1158   @retval EFI_UNSUPPORTED        The output device does not support visibility control of the cursor.
1159 
1160 **/
1161 EFI_STATUS
1162 EFIAPI
VgaClassEnableCursor(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN BOOLEAN Visible)1163 VgaClassEnableCursor (
1164   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1165   IN  BOOLEAN                         Visible
1166   )
1167 {
1168   VGA_CLASS_DEV *VgaClassDev;
1169 
1170   VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
1171   if (Visible) {
1172     if (This->Mode->Mode == 1) {
1173       //
1174       // 80 * 50
1175       //
1176       WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x06);
1177       WriteCrtc (VgaClassDev, CRTC_CURSOR_END, 0x07);
1178     } else {
1179       //
1180       // 80 * 25
1181       //
1182       WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x0e);
1183       WriteCrtc (VgaClassDev, CRTC_CURSOR_END, 0x0f);
1184     }
1185   } else {
1186     WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x20);
1187   }
1188 
1189   This->Mode->CursorVisible = Visible;
1190   return EFI_SUCCESS;
1191 }
1192 
1193 /**
1194   Returns information for an available text mode that the output device(s) supports.
1195 
1196   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
1197   It returns information for an available text mode that the output device(s) supports.
1198   It is required that all output devices support at least 80x25 text mode. This mode is defined to be mode 0.
1199   If the output devices support 80x50, that is defined to be mode 1.
1200 
1201   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1202   @param  ModeNumber             The mode number to return information on.
1203   @param  Columns                Columen in current mode number
1204   @param  Rows                   Row in current mode number.
1205 
1206   @retval EFI_SUCCESS            The requested mode information was returned.
1207   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request.
1208   @retval EFI_UNSUPPORTED        The mode number was not valid.
1209 
1210 **/
1211 EFI_STATUS
1212 EFIAPI
VgaClassQueryMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber,OUT UINTN * Columns,OUT UINTN * Rows)1213 VgaClassQueryMode (
1214   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1215   IN  UINTN                           ModeNumber,
1216   OUT UINTN                           *Columns,
1217   OUT UINTN                           *Rows
1218   )
1219 {
1220   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
1221     *Columns  = 0;
1222     *Rows     = 0;
1223     return EFI_UNSUPPORTED;
1224   }
1225 
1226   switch (ModeNumber) {
1227   case 0:
1228     *Columns  = 80;
1229     *Rows     = 25;
1230     break;
1231 
1232   case 1:
1233     *Columns  = 80;
1234     *Rows     = 50;
1235     break;
1236 
1237   default:
1238     *Columns  = 0;
1239     *Rows     = 0;
1240     return EFI_UNSUPPORTED;
1241   }
1242 
1243   return EFI_SUCCESS;
1244 }
1245 
1246 /**
1247   Sets the output device(s) to a specified mode.
1248 
1249   This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
1250   It sets the output device(s) to the requested mode.
1251   On success the device is in the geometry for the requested mode,
1252   and the device has been cleared to the current background color with the cursor at (0,0).
1253 
1254   @param  This                   Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
1255   @param  ModeNumber             The text mode to set.
1256 
1257   @retval EFI_SUCCESS            The requested text mode was set.
1258   @retval EFI_DEVICE_ERROR       The device had an error and could not complete the request.
1259   @retval EFI_UNSUPPORTED        The mode number was not valid.
1260 
1261 **/
1262 EFI_STATUS
1263 EFIAPI
VgaClassSetMode(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * This,IN UINTN ModeNumber)1264 VgaClassSetMode (
1265   IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1266   IN  UINTN                           ModeNumber
1267   )
1268 {
1269   VGA_CLASS_DEV *VgaClassDev;
1270 
1271   VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
1272 
1273   if ((INT32) ModeNumber >= This->Mode->MaxMode) {
1274     return EFI_UNSUPPORTED;
1275   }
1276 
1277   This->ClearScreen (This);
1278 
1279   This->Mode->Mode  = (INT32) ModeNumber;
1280 
1281   return VgaClassDev->VgaMiniPort->SetMode (VgaClassDev->VgaMiniPort, ModeNumber);
1282 }
1283