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