Home | History | Annotate | Download | only in GraphicsOutputDxe
      1 /** @file
      2   Implementation for a generic GOP driver.
      3 
      4 Copyright (c) 2016, 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 
     16 #include "GraphicsOutput.h"
     17 CONST ACPI_ADR_DEVICE_PATH mGraphicsOutputAdrNode = {
     18   {
     19     ACPI_DEVICE_PATH,
     20     ACPI_ADR_DP,
     21     { sizeof (ACPI_ADR_DEVICE_PATH), 0 },
     22   },
     23   ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0)
     24 };
     25 
     26 EFI_PEI_GRAPHICS_DEVICE_INFO_HOB mDefaultGraphicsDeviceInfo = {
     27   MAX_UINT16, MAX_UINT16, MAX_UINT16, MAX_UINT16, MAX_UINT8, MAX_UINT8
     28 };
     29 
     30 //
     31 // The driver should only start on one graphics controller.
     32 // So a global flag is used to remember that the driver is already started.
     33 //
     34 BOOLEAN mDriverStarted = FALSE;
     35 
     36 /**
     37   Returns information for an available graphics mode that the graphics device
     38   and the set of active video output devices supports.
     39 
     40   @param  This                  The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
     41   @param  ModeNumber            The mode number to return information on.
     42   @param  SizeOfInfo            A pointer to the size, in bytes, of the Info buffer.
     43   @param  Info                  A pointer to callee allocated buffer that returns information about ModeNumber.
     44 
     45   @retval EFI_SUCCESS           Valid mode information was returned.
     46   @retval EFI_DEVICE_ERROR      A hardware error occurred trying to retrieve the video mode.
     47   @retval EFI_INVALID_PARAMETER ModeNumber is not valid.
     48 
     49 **/
     50 EFI_STATUS
     51 EFIAPI
     52 GraphicsOutputQueryMode (
     53   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL          *This,
     54   IN  UINT32                                ModeNumber,
     55   OUT UINTN                                 *SizeOfInfo,
     56   OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  **Info
     57   )
     58 {
     59   if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
     60     return EFI_INVALID_PARAMETER;
     61   }
     62 
     63   *SizeOfInfo = This->Mode->SizeOfInfo;
     64   *Info       = AllocateCopyPool (*SizeOfInfo, This->Mode->Info);
     65   return EFI_SUCCESS;
     66 }
     67 
     68 /**
     69   Set the video device into the specified mode and clears the visible portions of
     70   the output display to black.
     71 
     72   @param  This              The EFI_GRAPHICS_OUTPUT_PROTOCOL instance.
     73   @param  ModeNumber        Abstraction that defines the current video mode.
     74 
     75   @retval EFI_SUCCESS       The graphics mode specified by ModeNumber was selected.
     76   @retval EFI_DEVICE_ERROR  The device had an error and could not complete the request.
     77   @retval EFI_UNSUPPORTED   ModeNumber is not supported by this device.
     78 
     79 **/
     80 EFI_STATUS
     81 EFIAPI
     82 GraphicsOutputSetMode (
     83   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
     84   IN  UINT32                       ModeNumber
     85 )
     86 {
     87   RETURN_STATUS                    Status;
     88   EFI_GRAPHICS_OUTPUT_BLT_PIXEL    Black;
     89   GRAPHICS_OUTPUT_PRIVATE_DATA     *Private;
     90 
     91   if (ModeNumber >= This->Mode->MaxMode) {
     92     return EFI_UNSUPPORTED;
     93   }
     94 
     95   Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (This);
     96 
     97   Black.Blue = 0;
     98   Black.Green = 0;
     99   Black.Red = 0;
    100   Black.Reserved = 0;
    101 
    102   Status = FrameBufferBlt (
    103              Private->FrameBufferBltLibConfigure,
    104              &Black,
    105              EfiBltVideoFill,
    106              0, 0,
    107              0, 0,
    108              This->Mode->Info->HorizontalResolution,
    109              This->Mode->Info->VerticalResolution,
    110              0
    111              );
    112   return RETURN_ERROR (Status) ? EFI_DEVICE_ERROR : EFI_SUCCESS;
    113 }
    114 
    115 /**
    116   Blt a rectangle of pixels on the graphics screen. Blt stands for BLock Transfer.
    117 
    118   @param  This         Protocol instance pointer.
    119   @param  BltBuffer    The data to transfer to the graphics screen.
    120                        Size is at least Width*Height*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL).
    121   @param  BltOperation The operation to perform when copying BltBuffer on to the graphics screen.
    122   @param  SourceX      The X coordinate of source for the BltOperation.
    123   @param  SourceY      The Y coordinate of source for the BltOperation.
    124   @param  DestinationX The X coordinate of destination for the BltOperation.
    125   @param  DestinationY The Y coordinate of destination for the BltOperation.
    126   @param  Width        The width of a rectangle in the blt rectangle in pixels.
    127   @param  Height       The height of a rectangle in the blt rectangle in pixels.
    128   @param  Delta        Not used for EfiBltVideoFill or the EfiBltVideoToVideo operation.
    129                        If a Delta of zero is used, the entire BltBuffer is being operated on.
    130                        If a subrectangle of the BltBuffer is being used then Delta
    131                        represents the number of bytes in a row of the BltBuffer.
    132 
    133   @retval EFI_SUCCESS           BltBuffer was drawn to the graphics screen.
    134   @retval EFI_INVALID_PARAMETER BltOperation is not valid.
    135   @retval EFI_DEVICE_ERROR      The device had an error and could not complete the request.
    136 
    137 **/
    138 EFI_STATUS
    139 EFIAPI
    140 GraphicsOutputBlt (
    141   IN  EFI_GRAPHICS_OUTPUT_PROTOCOL      *This,
    142   IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *BltBuffer, OPTIONAL
    143   IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
    144   IN  UINTN                             SourceX,
    145   IN  UINTN                             SourceY,
    146   IN  UINTN                             DestinationX,
    147   IN  UINTN                             DestinationY,
    148   IN  UINTN                             Width,
    149   IN  UINTN                             Height,
    150   IN  UINTN                             Delta         OPTIONAL
    151   )
    152 {
    153   RETURN_STATUS                         Status;
    154   EFI_TPL                               Tpl;
    155   GRAPHICS_OUTPUT_PRIVATE_DATA          *Private;
    156 
    157   Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (This);
    158   //
    159   // We have to raise to TPL_NOTIFY, so we make an atomic write to the frame buffer.
    160   // We would not want a timer based event (Cursor, ...) to come in while we are
    161   // doing this operation.
    162   //
    163   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    164   Status = FrameBufferBlt (
    165              Private->FrameBufferBltLibConfigure,
    166              BltBuffer,
    167              BltOperation,
    168              SourceX, SourceY,
    169              DestinationX, DestinationY, Width, Height,
    170              Delta
    171              );
    172   gBS->RestoreTPL (Tpl);
    173 
    174   return RETURN_ERROR (Status) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
    175 }
    176 
    177 CONST GRAPHICS_OUTPUT_PRIVATE_DATA mGraphicsOutputInstanceTemplate = {
    178   GRAPHICS_OUTPUT_PRIVATE_DATA_SIGNATURE,          // Signature
    179   NULL,                                            // GraphicsOutputHandle
    180   {
    181     GraphicsOutputQueryMode,
    182     GraphicsOutputSetMode,
    183     GraphicsOutputBlt,
    184     NULL                                           // Mode
    185   },
    186   {
    187     1,                                             // MaxMode
    188     0,                                             // Mode
    189     NULL,                                          // Info
    190     sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), // SizeOfInfo
    191     0,                                             // FrameBufferBase
    192     0                                              // FrameBufferSize
    193   },
    194   NULL,                                            // DevicePath
    195   NULL,                                            // PciIo
    196   0,                                               // PciAttributes
    197   NULL,                                            // FrameBufferBltLibConfigure
    198   0                                                // FrameBufferBltLibConfigureSize
    199 };
    200 
    201 /**
    202   Test whether the Controller can be managed by the driver.
    203 
    204   @param  This                 Driver Binding protocol instance pointer.
    205   @param  Controller           The PCI controller.
    206   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    207                                device to start.
    208 
    209   @retval EFI_SUCCESS          The driver can manage the video device.
    210   @retval other                The driver cannot manage the video device.
    211 **/
    212 EFI_STATUS
    213 EFIAPI
    214 GraphicsOutputDriverBindingSupported (
    215   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    216   IN EFI_HANDLE                     Controller,
    217   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    218   )
    219 {
    220   EFI_STATUS                        Status;
    221   EFI_PCI_IO_PROTOCOL               *PciIo;
    222   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
    223 
    224   //
    225   // Since there is only one GraphicsInfo HOB, the driver only manages one video device.
    226   //
    227   if (mDriverStarted) {
    228     return EFI_ALREADY_STARTED;
    229   }
    230 
    231   //
    232   // Test the PCI I/O Protocol
    233   //
    234   Status = gBS->OpenProtocol (
    235                   Controller,
    236                   &gEfiPciIoProtocolGuid,
    237                   (VOID **) &PciIo,
    238                   This->DriverBindingHandle,
    239                   Controller,
    240                   EFI_OPEN_PROTOCOL_BY_DRIVER
    241                   );
    242   if (Status == EFI_ALREADY_STARTED) {
    243     Status = EFI_SUCCESS;
    244   }
    245   if (EFI_ERROR (Status)) {
    246     return Status;
    247   }
    248   gBS->CloseProtocol (
    249          Controller,
    250          &gEfiPciIoProtocolGuid,
    251          This->DriverBindingHandle,
    252          Controller
    253          );
    254 
    255   //
    256   // Test the DevicePath protocol
    257   //
    258   Status = gBS->OpenProtocol (
    259                   Controller,
    260                   &gEfiDevicePathProtocolGuid,
    261                   (VOID **) &DevicePath,
    262                   This->DriverBindingHandle,
    263                   Controller,
    264                   EFI_OPEN_PROTOCOL_BY_DRIVER
    265                   );
    266   if (Status == EFI_ALREADY_STARTED) {
    267     Status = EFI_SUCCESS;
    268   }
    269   if (EFI_ERROR (Status)) {
    270     return Status;
    271   }
    272   gBS->CloseProtocol (
    273          Controller,
    274          &gEfiDevicePathProtocolGuid,
    275          This->DriverBindingHandle,
    276          Controller
    277          );
    278 
    279   if ((RemainingDevicePath == NULL) ||
    280       IsDevicePathEnd (RemainingDevicePath) ||
    281       CompareMem (RemainingDevicePath, &mGraphicsOutputAdrNode, sizeof (mGraphicsOutputAdrNode)) == 0) {
    282     return EFI_SUCCESS;
    283   } else {
    284     return EFI_INVALID_PARAMETER;
    285   }
    286 }
    287 
    288 /**
    289   Start the video controller.
    290 
    291   @param  This                 Driver Binding protocol instance pointer.
    292   @param  ControllerHandle     The PCI controller.
    293   @param  RemainingDevicePath  Optional parameter use to pick a specific child
    294                                device to start.
    295 
    296   @retval EFI_SUCCESS          The driver starts to manage the video device.
    297   @retval other                The driver cannot manage the video device.
    298 **/
    299 EFI_STATUS
    300 EFIAPI
    301 GraphicsOutputDriverBindingStart (
    302   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    303   IN EFI_HANDLE                     Controller,
    304   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    305   )
    306 {
    307   EFI_STATUS                        Status;
    308   RETURN_STATUS                     ReturnStatus;
    309   GRAPHICS_OUTPUT_PRIVATE_DATA      *Private;
    310   EFI_PCI_IO_PROTOCOL               *PciIo;
    311   EFI_DEVICE_PATH                   *PciDevicePath;
    312   PCI_TYPE00                        Pci;
    313   UINT8                             Index;
    314   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
    315   VOID                              *HobStart;
    316   EFI_PEI_GRAPHICS_INFO_HOB         *GraphicsInfo;
    317   EFI_PEI_GRAPHICS_DEVICE_INFO_HOB  *DeviceInfo;
    318   EFI_PHYSICAL_ADDRESS              FrameBufferBase;
    319 
    320   FrameBufferBase = 0;
    321 
    322   HobStart = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid);
    323   ASSERT ((HobStart != NULL) && (GET_GUID_HOB_DATA_SIZE (HobStart) == sizeof (EFI_PEI_GRAPHICS_INFO_HOB)));
    324   GraphicsInfo = (EFI_PEI_GRAPHICS_INFO_HOB *) (GET_GUID_HOB_DATA (HobStart));
    325 
    326   HobStart = GetFirstGuidHob (&gEfiGraphicsDeviceInfoHobGuid);
    327   if ((HobStart == NULL) || (GET_GUID_HOB_DATA_SIZE (HobStart) < sizeof (*DeviceInfo))) {
    328     //
    329     // Use default device infomation when the device info HOB doesn't exist
    330     //
    331     DeviceInfo = &mDefaultGraphicsDeviceInfo;
    332     DEBUG ((EFI_D_INFO, "[%a]: GraphicsDeviceInfo HOB doesn't exist!\n", gEfiCallerBaseName));
    333   } else {
    334     DeviceInfo = (EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *) (GET_GUID_HOB_DATA (HobStart));
    335     DEBUG ((EFI_D_INFO, "[%a]: GraphicsDeviceInfo HOB:\n"
    336             "  VendorId = %04x, DeviceId = %04x,\n"
    337             "  RevisionId = %02x, BarIndex = %x,\n"
    338             "  SubsystemVendorId = %04x, SubsystemId = %04x\n",
    339             gEfiCallerBaseName,
    340             DeviceInfo->VendorId, DeviceInfo->DeviceId,
    341             DeviceInfo->RevisionId, DeviceInfo->BarIndex,
    342             DeviceInfo->SubsystemVendorId, DeviceInfo->SubsystemId));
    343   }
    344 
    345   //
    346   // Open the PCI I/O Protocol
    347   //
    348   Status = gBS->OpenProtocol (
    349                   Controller,
    350                   &gEfiPciIoProtocolGuid,
    351                   (VOID **) &PciIo,
    352                   This->DriverBindingHandle,
    353                   Controller,
    354                   EFI_OPEN_PROTOCOL_BY_DRIVER
    355                   );
    356   if (Status == EFI_ALREADY_STARTED) {
    357     Status = EFI_SUCCESS;
    358   }
    359   ASSERT_EFI_ERROR (Status);
    360 
    361   Status = gBS->OpenProtocol (
    362                   Controller,
    363                   &gEfiDevicePathProtocolGuid,
    364                   (VOID **) &PciDevicePath,
    365                   This->DriverBindingHandle,
    366                   Controller,
    367                   EFI_OPEN_PROTOCOL_BY_DRIVER
    368                   );
    369   if (Status == EFI_ALREADY_STARTED) {
    370     Status = EFI_SUCCESS;
    371   }
    372   ASSERT_EFI_ERROR (Status);
    373 
    374   //
    375   // Read the PCI Class Code from the PCI Device
    376   //
    377   Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (Pci), &Pci);
    378   if (!EFI_ERROR (Status)) {
    379     if (!IS_PCI_DISPLAY (&Pci) || (
    380         ((DeviceInfo->VendorId != MAX_UINT16) && (DeviceInfo->VendorId != Pci.Hdr.VendorId)) ||
    381         ((DeviceInfo->DeviceId != MAX_UINT16) && (DeviceInfo->DeviceId != Pci.Hdr.DeviceId)) ||
    382         ((DeviceInfo->RevisionId != MAX_UINT8) && (DeviceInfo->RevisionId != Pci.Hdr.RevisionID)) ||
    383         ((DeviceInfo->SubsystemVendorId != MAX_UINT16) && (DeviceInfo->SubsystemVendorId != Pci.Device.SubsystemVendorID)) ||
    384         ((DeviceInfo->SubsystemId != MAX_UINT16) && (DeviceInfo->SubsystemId != Pci.Device.SubsystemID))
    385         )
    386         ) {
    387       //
    388       // It's not a video device, or device infomation doesn't match.
    389       //
    390       Status = EFI_UNSUPPORTED;
    391     } else {
    392       //
    393       // If it's a video device and device information matches, use the BarIndex
    394       // from device information, or any BAR if BarIndex is not specified
    395       // whose size >= the frame buffer size from GraphicsInfo HOB.
    396       // Store the new frame buffer base.
    397       //
    398       for (Index = 0; Index < MAX_PCI_BAR; Index++) {
    399         if ((DeviceInfo->BarIndex != MAX_UINT8) && (DeviceInfo->BarIndex != Index)) {
    400           continue;
    401         }
    402         Status = PciIo->GetBarAttributes (PciIo, Index, NULL, (VOID**) &Resources);
    403         if (!EFI_ERROR (Status)) {
    404           DEBUG ((EFI_D_INFO, "[%a]: BAR[%d]: Base = %lx, Length = %lx\n",
    405                   gEfiCallerBaseName, Index, Resources->AddrRangeMin, Resources->AddrLen));
    406           if ((Resources->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) &&
    407             (Resources->Len == (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3)) &&
    408               (Resources->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) &&
    409               (Resources->AddrLen >= GraphicsInfo->FrameBufferSize)
    410               ) {
    411             FrameBufferBase = Resources->AddrRangeMin;
    412             DEBUG ((EFI_D_INFO, "[%a]: ... matched!\n", gEfiCallerBaseName));
    413             break;
    414           }
    415         }
    416       }
    417       if (Index == MAX_PCI_BAR) {
    418         Status = EFI_UNSUPPORTED;
    419       }
    420     }
    421   }
    422 
    423   if (EFI_ERROR (Status)) {
    424     goto CloseProtocols;
    425   }
    426 
    427   if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) {
    428     return EFI_SUCCESS;
    429   }
    430 
    431   Private = AllocateCopyPool (sizeof (mGraphicsOutputInstanceTemplate), &mGraphicsOutputInstanceTemplate);
    432   if (Private == NULL) {
    433     Status = EFI_OUT_OF_RESOURCES;
    434     goto CloseProtocols;
    435   }
    436 
    437   Private->GraphicsOutputMode.FrameBufferBase = FrameBufferBase;
    438   Private->GraphicsOutputMode.FrameBufferSize = GraphicsInfo->FrameBufferSize;
    439   Private->GraphicsOutputMode.Info = &GraphicsInfo->GraphicsMode;
    440 
    441   //
    442   // Fix up Mode pointer in GraphicsOutput
    443   //
    444   Private->GraphicsOutput.Mode = &Private->GraphicsOutputMode;
    445 
    446   //
    447   // Set attributes
    448   //
    449   Status = PciIo->Attributes (
    450                     PciIo,
    451                     EfiPciIoAttributeOperationGet,
    452                     0,
    453                     &Private->PciAttributes
    454                     );
    455   if (!EFI_ERROR (Status)) {
    456     Status = PciIo->Attributes (
    457                       PciIo,
    458                       EfiPciIoAttributeOperationEnable,
    459                       EFI_PCI_DEVICE_ENABLE,
    460                       NULL
    461                       );
    462   }
    463 
    464   if (EFI_ERROR (Status)) {
    465     goto FreeMemory;
    466   }
    467 
    468   //
    469   // Create the FrameBufferBltLib configuration.
    470   //
    471   ReturnStatus = FrameBufferBltConfigure (
    472                    (VOID *) (UINTN) Private->GraphicsOutput.Mode->FrameBufferBase,
    473                    Private->GraphicsOutput.Mode->Info,
    474                    Private->FrameBufferBltLibConfigure,
    475                    &Private->FrameBufferBltLibConfigureSize
    476                    );
    477   if (ReturnStatus == RETURN_BUFFER_TOO_SMALL) {
    478     Private->FrameBufferBltLibConfigure = AllocatePool (Private->FrameBufferBltLibConfigureSize);
    479     if (Private->FrameBufferBltLibConfigure != NULL) {
    480       ReturnStatus = FrameBufferBltConfigure (
    481                        (VOID *) (UINTN) Private->GraphicsOutput.Mode->FrameBufferBase,
    482                        Private->GraphicsOutput.Mode->Info,
    483                        Private->FrameBufferBltLibConfigure,
    484                        &Private->FrameBufferBltLibConfigureSize
    485                        );
    486     }
    487   }
    488   if (RETURN_ERROR (ReturnStatus)) {
    489     Status = EFI_OUT_OF_RESOURCES;
    490     goto RestorePciAttributes;
    491   }
    492 
    493   Private->DevicePath = AppendDevicePathNode (PciDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &mGraphicsOutputAdrNode);
    494   if (Private->DevicePath == NULL) {
    495     Status = EFI_OUT_OF_RESOURCES;
    496     goto RestorePciAttributes;
    497   }
    498 
    499   Status = gBS->InstallMultipleProtocolInterfaces (
    500                   &Private->GraphicsOutputHandle,
    501                   &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
    502                   &gEfiDevicePathProtocolGuid, Private->DevicePath,
    503                   NULL
    504                   );
    505 
    506   if (!EFI_ERROR (Status)) {
    507     Status = gBS->OpenProtocol (
    508                     Controller,
    509                     &gEfiPciIoProtocolGuid,
    510                     (VOID **) &Private->PciIo,
    511                     This->DriverBindingHandle,
    512                     Private->GraphicsOutputHandle,
    513                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    514                     );
    515     if (!EFI_ERROR (Status)) {
    516       mDriverStarted = TRUE;
    517     } else {
    518       gBS->UninstallMultipleProtocolInterfaces (
    519              Private->GraphicsOutputHandle,
    520              &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
    521              &gEfiDevicePathProtocolGuid, Private->DevicePath,
    522              NULL
    523              );
    524     }
    525   }
    526 
    527 RestorePciAttributes:
    528   if (EFI_ERROR (Status)) {
    529     //
    530     // Restore original PCI attributes
    531     //
    532     PciIo->Attributes (
    533              PciIo,
    534              EfiPciIoAttributeOperationSet,
    535              Private->PciAttributes,
    536              NULL
    537              );
    538   }
    539 
    540 FreeMemory:
    541   if (EFI_ERROR (Status)) {
    542     if (Private != NULL) {
    543       if (Private->DevicePath != NULL) {
    544         FreePool (Private->DevicePath);
    545       }
    546       if (Private->FrameBufferBltLibConfigure != NULL) {
    547         FreePool (Private->FrameBufferBltLibConfigure);
    548       }
    549       FreePool (Private);
    550     }
    551   }
    552 
    553 CloseProtocols:
    554   if (EFI_ERROR (Status)) {
    555     //
    556     // Close the PCI I/O Protocol
    557     //
    558     gBS->CloseProtocol (
    559            Controller,
    560            &gEfiDevicePathProtocolGuid,
    561            This->DriverBindingHandle,
    562            Controller
    563            );
    564 
    565     //
    566     // Close the PCI I/O Protocol
    567     //
    568     gBS->CloseProtocol (
    569            Controller,
    570            &gEfiPciIoProtocolGuid,
    571            This->DriverBindingHandle,
    572            Controller
    573            );
    574   }
    575   return Status;
    576 }
    577 
    578 /**
    579   Stop the video controller.
    580 
    581   @param  This                 Driver Binding protocol instance pointer.
    582   @param  Controller           The PCI controller.
    583   @param  NumberOfChildren     The number of child device handles in ChildHandleBuffer.
    584   @param  ChildHandleBuffer    An array of child handles to be freed. May be NULL
    585                                if NumberOfChildren is 0.
    586 
    587   @retval EFI_SUCCESS          The device was stopped.
    588   @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.
    589 **/
    590 EFI_STATUS
    591 EFIAPI
    592 GraphicsOutputDriverBindingStop (
    593   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    594   IN EFI_HANDLE                     Controller,
    595   IN UINTN                          NumberOfChildren,
    596   IN EFI_HANDLE                     *ChildHandleBuffer
    597   )
    598 {
    599   EFI_STATUS                        Status;
    600   EFI_GRAPHICS_OUTPUT_PROTOCOL      *Gop;
    601   GRAPHICS_OUTPUT_PRIVATE_DATA      *Private;
    602 
    603   if (NumberOfChildren == 0) {
    604 
    605     //
    606     // Close the PCI I/O Protocol
    607     //
    608     Status = gBS->CloseProtocol (
    609                     Controller,
    610                     &gEfiPciIoProtocolGuid,
    611                     This->DriverBindingHandle,
    612                     Controller
    613                     );
    614     ASSERT_EFI_ERROR (Status);
    615 
    616     Status = gBS->CloseProtocol (
    617                     Controller,
    618                     &gEfiDevicePathProtocolGuid,
    619                     This->DriverBindingHandle,
    620                     Controller
    621                     );
    622     ASSERT_EFI_ERROR (Status);
    623     return EFI_SUCCESS;
    624   }
    625 
    626   ASSERT (NumberOfChildren == 1);
    627   Status = gBS->OpenProtocol (
    628                   ChildHandleBuffer[0],
    629                   &gEfiGraphicsOutputProtocolGuid,
    630                   (VOID **) &Gop,
    631                   This->DriverBindingHandle,
    632                   ChildHandleBuffer[0],
    633                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    634                   );
    635   if (EFI_ERROR (Status)) {
    636     return Status;
    637   }
    638 
    639   Private = GRAPHICS_OUTPUT_PRIVATE_FROM_THIS (Gop);
    640 
    641   Status = gBS->CloseProtocol (
    642                   Controller,
    643                   &gEfiPciIoProtocolGuid,
    644                   This->DriverBindingHandle,
    645                   Private->GraphicsOutputHandle
    646                   );
    647   ASSERT_EFI_ERROR (Status);
    648   //
    649   // Remove the GOP protocol interface from the system
    650   //
    651   Status = gBS->UninstallMultipleProtocolInterfaces (
    652                   Private->GraphicsOutputHandle,
    653                   &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput,
    654                   &gEfiDevicePathProtocolGuid, Private->DevicePath,
    655                   NULL
    656                   );
    657   if (!EFI_ERROR (Status)) {
    658     //
    659     // Restore original PCI attributes
    660     //
    661     Status = Private->PciIo->Attributes (
    662                                Private->PciIo,
    663                                EfiPciIoAttributeOperationSet,
    664                                Private->PciAttributes,
    665                                NULL
    666                                );
    667     ASSERT_EFI_ERROR (Status);
    668 
    669     FreePool (Private->DevicePath);
    670     FreePool (Private->FrameBufferBltLibConfigure);
    671     mDriverStarted = FALSE;
    672   } else {
    673     Status = gBS->OpenProtocol (
    674                     Controller,
    675                     &gEfiPciIoProtocolGuid,
    676                     (VOID **) &Private->PciIo,
    677                     This->DriverBindingHandle,
    678                     Private->GraphicsOutputHandle,
    679                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    680                     );
    681     ASSERT_EFI_ERROR (Status);
    682   }
    683   return Status;
    684 }
    685 
    686 EFI_DRIVER_BINDING_PROTOCOL mGraphicsOutputDriverBinding = {
    687   GraphicsOutputDriverBindingSupported,
    688   GraphicsOutputDriverBindingStart,
    689   GraphicsOutputDriverBindingStop,
    690   0x10,
    691   NULL,
    692   NULL
    693 };
    694 
    695 /**
    696   The Entry Point for GraphicsOutput driver.
    697 
    698   It installs DriverBinding, ComponentName and ComponentName2 protocol if there is
    699   GraphicsInfo HOB passed from Graphics PEIM.
    700 
    701   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
    702   @param[in] SystemTable    A pointer to the EFI System Table.
    703 
    704   @retval EFI_SUCCESS       The entry point is executed successfully.
    705   @retval other             Some error occurs when executing this entry point.
    706 
    707 **/
    708 EFI_STATUS
    709 EFIAPI
    710 InitializeGraphicsOutput (
    711   IN EFI_HANDLE                        ImageHandle,
    712   IN EFI_SYSTEM_TABLE                  *SystemTable
    713   )
    714 {
    715   EFI_STATUS                           Status;
    716   VOID                                 *HobStart;
    717 
    718   HobStart = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid);
    719 
    720   if ((HobStart == NULL) || (GET_GUID_HOB_DATA_SIZE (HobStart) < sizeof (EFI_PEI_GRAPHICS_INFO_HOB))) {
    721     return EFI_NOT_FOUND;
    722   }
    723 
    724   Status = EfiLibInstallDriverBindingComponentName2 (
    725              ImageHandle,
    726              SystemTable,
    727              &mGraphicsOutputDriverBinding,
    728              ImageHandle,
    729              &mGraphicsOutputComponentName,
    730              &mGraphicsOutputComponentName2
    731              );
    732   ASSERT_EFI_ERROR (Status);
    733 
    734   return Status;
    735 }
    736