Home | History | Annotate | Download | only in QemuVideoDxe
      1 /** @file
      2   This driver is a sample implementation of the Graphics Output Protocol for
      3   the QEMU (Cirrus Logic 5446) video controller.
      4 
      5   Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution. The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Qemu.h"
     18 #include <IndustryStandard/Acpi.h>
     19 
     20 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
     21   QemuVideoControllerDriverSupported,
     22   QemuVideoControllerDriverStart,
     23   QemuVideoControllerDriverStop,
     24   0x10,
     25   NULL,
     26   NULL
     27 };
     28 
     29 QEMU_VIDEO_CARD gQemuVideoCardList[] = {
     30     {
     31         CIRRUS_LOGIC_VENDOR_ID,
     32         CIRRUS_LOGIC_5430_DEVICE_ID,
     33         QEMU_VIDEO_CIRRUS_5430,
     34         L"Cirrus 5430"
     35     },{
     36         CIRRUS_LOGIC_VENDOR_ID,
     37         CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
     38         QEMU_VIDEO_CIRRUS_5430,
     39         L"Cirrus 5430"
     40     },{
     41         CIRRUS_LOGIC_VENDOR_ID,
     42         CIRRUS_LOGIC_5446_DEVICE_ID,
     43         QEMU_VIDEO_CIRRUS_5446,
     44         L"Cirrus 5446"
     45     },{
     46         0x1234,
     47         0x1111,
     48         QEMU_VIDEO_BOCHS_MMIO,
     49         L"QEMU Standard VGA"
     50     },{
     51         0x1b36,
     52         0x0100,
     53         QEMU_VIDEO_BOCHS,
     54         L"QEMU QXL VGA"
     55     },{
     56         0x1af4,
     57         0x1050,
     58         QEMU_VIDEO_BOCHS_MMIO,
     59         L"QEMU VirtIO VGA"
     60     },{
     61         0 /* end of list */
     62     }
     63 };
     64 
     65 static QEMU_VIDEO_CARD*
     66 QemuVideoDetect(
     67   IN UINT16 VendorId,
     68   IN UINT16 DeviceId
     69   )
     70 {
     71   UINTN Index = 0;
     72 
     73   while (gQemuVideoCardList[Index].VendorId != 0) {
     74     if (gQemuVideoCardList[Index].VendorId == VendorId &&
     75         gQemuVideoCardList[Index].DeviceId == DeviceId) {
     76       return gQemuVideoCardList + Index;
     77     }
     78     Index++;
     79   }
     80   return NULL;
     81 }
     82 
     83 /**
     84   Check if this device is supported.
     85 
     86   @param  This                   The driver binding protocol.
     87   @param  Controller             The controller handle to check.
     88   @param  RemainingDevicePath    The remaining device path.
     89 
     90   @retval EFI_SUCCESS            The bus supports this controller.
     91   @retval EFI_UNSUPPORTED        This device isn't supported.
     92 
     93 **/
     94 EFI_STATUS
     95 EFIAPI
     96 QemuVideoControllerDriverSupported (
     97   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     98   IN EFI_HANDLE                     Controller,
     99   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    100   )
    101 {
    102   EFI_STATUS          Status;
    103   EFI_PCI_IO_PROTOCOL *PciIo;
    104   PCI_TYPE00          Pci;
    105   QEMU_VIDEO_CARD     *Card;
    106 
    107   //
    108   // Open the PCI I/O Protocol
    109   //
    110   Status = gBS->OpenProtocol (
    111                   Controller,
    112                   &gEfiPciIoProtocolGuid,
    113                   (VOID **) &PciIo,
    114                   This->DriverBindingHandle,
    115                   Controller,
    116                   EFI_OPEN_PROTOCOL_BY_DRIVER
    117                   );
    118   if (EFI_ERROR (Status)) {
    119     return Status;
    120   }
    121 
    122   //
    123   // Read the PCI Configuration Header from the PCI Device
    124   //
    125   Status = PciIo->Pci.Read (
    126                         PciIo,
    127                         EfiPciIoWidthUint32,
    128                         0,
    129                         sizeof (Pci) / sizeof (UINT32),
    130                         &Pci
    131                         );
    132   if (EFI_ERROR (Status)) {
    133     goto Done;
    134   }
    135 
    136   Status = EFI_UNSUPPORTED;
    137   if (!IS_PCI_VGA (&Pci)) {
    138     goto Done;
    139   }
    140   Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
    141   if (Card != NULL) {
    142     DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));
    143     Status = EFI_SUCCESS;
    144   }
    145 
    146 Done:
    147   //
    148   // Close the PCI I/O Protocol
    149   //
    150   gBS->CloseProtocol (
    151         Controller,
    152         &gEfiPciIoProtocolGuid,
    153         This->DriverBindingHandle,
    154         Controller
    155         );
    156 
    157   return Status;
    158 }
    159 
    160 /**
    161   Start to process the controller.
    162 
    163   @param  This                   The USB bus driver binding instance.
    164   @param  Controller             The controller to check.
    165   @param  RemainingDevicePath    The remaining device patch.
    166 
    167   @retval EFI_SUCCESS            The controller is controlled by the usb bus.
    168   @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb
    169                                  bus.
    170   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.
    171 
    172 **/
    173 EFI_STATUS
    174 EFIAPI
    175 QemuVideoControllerDriverStart (
    176   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    177   IN EFI_HANDLE                     Controller,
    178   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
    179   )
    180 {
    181   EFI_TPL                           OldTpl;
    182   EFI_STATUS                        Status;
    183   QEMU_VIDEO_PRIVATE_DATA           *Private;
    184   BOOLEAN                           IsQxl;
    185   EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;
    186   ACPI_ADR_DEVICE_PATH              AcpiDeviceNode;
    187   PCI_TYPE00                        Pci;
    188   QEMU_VIDEO_CARD                   *Card;
    189   EFI_PCI_IO_PROTOCOL               *ChildPciIo;
    190 
    191   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    192 
    193   //
    194   // Allocate Private context data for GOP inteface.
    195   //
    196   Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
    197   if (Private == NULL) {
    198     Status = EFI_OUT_OF_RESOURCES;
    199     goto RestoreTpl;
    200   }
    201 
    202   //
    203   // Set up context record
    204   //
    205   Private->Signature  = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
    206 
    207   //
    208   // Open PCI I/O Protocol
    209   //
    210   Status = gBS->OpenProtocol (
    211                   Controller,
    212                   &gEfiPciIoProtocolGuid,
    213                   (VOID **) &Private->PciIo,
    214                   This->DriverBindingHandle,
    215                   Controller,
    216                   EFI_OPEN_PROTOCOL_BY_DRIVER
    217                   );
    218   if (EFI_ERROR (Status)) {
    219     goto FreePrivate;
    220   }
    221 
    222   //
    223   // Read the PCI Configuration Header from the PCI Device
    224   //
    225   Status = Private->PciIo->Pci.Read (
    226                         Private->PciIo,
    227                         EfiPciIoWidthUint32,
    228                         0,
    229                         sizeof (Pci) / sizeof (UINT32),
    230                         &Pci
    231                         );
    232   if (EFI_ERROR (Status)) {
    233     goto ClosePciIo;
    234   }
    235 
    236   //
    237   // Determine card variant.
    238   //
    239   Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
    240   if (Card == NULL) {
    241     Status = EFI_DEVICE_ERROR;
    242     goto ClosePciIo;
    243   }
    244   Private->Variant = Card->Variant;
    245 
    246   //
    247   // IsQxl is based on the detected Card->Variant, which at a later point might
    248   // not match Private->Variant.
    249   //
    250   IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);
    251 
    252   //
    253   // Save original PCI attributes
    254   //
    255   Status = Private->PciIo->Attributes (
    256                     Private->PciIo,
    257                     EfiPciIoAttributeOperationGet,
    258                     0,
    259                     &Private->OriginalPciAttributes
    260                     );
    261 
    262   if (EFI_ERROR (Status)) {
    263     goto ClosePciIo;
    264   }
    265 
    266   //
    267   // Set new PCI attributes
    268   //
    269   Status = Private->PciIo->Attributes (
    270                             Private->PciIo,
    271                             EfiPciIoAttributeOperationEnable,
    272                             EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
    273                             NULL
    274                             );
    275   if (EFI_ERROR (Status)) {
    276     goto ClosePciIo;
    277   }
    278 
    279   //
    280   // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
    281   //
    282   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
    283     EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
    284 
    285     Status = Private->PciIo->GetBarAttributes (
    286                         Private->PciIo,
    287                         PCI_BAR_IDX2,
    288                         NULL,
    289                         (VOID**) &MmioDesc
    290                         );
    291     if (EFI_ERROR (Status) ||
    292         MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
    293       DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
    294       Private->Variant = QEMU_VIDEO_BOCHS;
    295     } else {
    296       DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
    297               MmioDesc->AddrRangeMin));
    298     }
    299 
    300     if (!EFI_ERROR (Status)) {
    301       FreePool (MmioDesc);
    302     }
    303   }
    304 
    305   //
    306   // Check if accessing the bochs interface works.
    307   //
    308   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
    309       Private->Variant == QEMU_VIDEO_BOCHS) {
    310     UINT16 BochsId;
    311     BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);
    312     if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
    313       DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
    314       Status = EFI_DEVICE_ERROR;
    315       goto RestoreAttributes;
    316     }
    317   }
    318 
    319   //
    320   // Get ParentDevicePath
    321   //
    322   Status = gBS->HandleProtocol (
    323                   Controller,
    324                   &gEfiDevicePathProtocolGuid,
    325                   (VOID **) &ParentDevicePath
    326                   );
    327   if (EFI_ERROR (Status)) {
    328     goto RestoreAttributes;
    329   }
    330 
    331   //
    332   // Set Gop Device Path
    333   //
    334   ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
    335   AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
    336   AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
    337   AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
    338   SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
    339 
    340   Private->GopDevicePath = AppendDevicePathNode (
    341                                       ParentDevicePath,
    342                                       (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
    343                                       );
    344   if (Private->GopDevicePath == NULL) {
    345     Status = EFI_OUT_OF_RESOURCES;
    346     goto RestoreAttributes;
    347   }
    348 
    349   //
    350   // Create new child handle and install the device path protocol on it.
    351   //
    352   Status = gBS->InstallMultipleProtocolInterfaces (
    353                   &Private->Handle,
    354                   &gEfiDevicePathProtocolGuid,
    355                   Private->GopDevicePath,
    356                   NULL
    357                   );
    358   if (EFI_ERROR (Status)) {
    359     goto FreeGopDevicePath;
    360   }
    361 
    362   //
    363   // Construct video mode buffer
    364   //
    365   switch (Private->Variant) {
    366   case QEMU_VIDEO_CIRRUS_5430:
    367   case QEMU_VIDEO_CIRRUS_5446:
    368     Status = QemuVideoCirrusModeSetup (Private);
    369     break;
    370   case QEMU_VIDEO_BOCHS_MMIO:
    371   case QEMU_VIDEO_BOCHS:
    372     Status = QemuVideoBochsModeSetup (Private, IsQxl);
    373     break;
    374   default:
    375     ASSERT (FALSE);
    376     Status = EFI_DEVICE_ERROR;
    377     break;
    378   }
    379   if (EFI_ERROR (Status)) {
    380     goto UninstallGopDevicePath;
    381   }
    382 
    383   //
    384   // Start the GOP software stack.
    385   //
    386   Status = QemuVideoGraphicsOutputConstructor (Private);
    387   if (EFI_ERROR (Status)) {
    388     goto FreeModeData;
    389   }
    390 
    391   Status = gBS->InstallMultipleProtocolInterfaces (
    392                   &Private->Handle,
    393                   &gEfiGraphicsOutputProtocolGuid,
    394                   &Private->GraphicsOutput,
    395                   NULL
    396                   );
    397   if (EFI_ERROR (Status)) {
    398     goto DestructQemuVideoGraphics;
    399   }
    400 
    401   //
    402   // Reference parent handle from child handle.
    403   //
    404   Status = gBS->OpenProtocol (
    405                 Controller,
    406                 &gEfiPciIoProtocolGuid,
    407                 (VOID **) &ChildPciIo,
    408                 This->DriverBindingHandle,
    409                 Private->Handle,
    410                 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    411                 );
    412   if (EFI_ERROR (Status)) {
    413     goto UninstallGop;
    414   }
    415 
    416 #if defined MDE_CPU_IA32 || defined MDE_CPU_X64
    417   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
    418       Private->Variant == QEMU_VIDEO_BOCHS) {
    419     InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
    420   }
    421 #endif
    422 
    423   gBS->RestoreTPL (OldTpl);
    424   return EFI_SUCCESS;
    425 
    426 UninstallGop:
    427   gBS->UninstallProtocolInterface (Private->Handle,
    428          &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);
    429 
    430 DestructQemuVideoGraphics:
    431   QemuVideoGraphicsOutputDestructor (Private);
    432 
    433 FreeModeData:
    434   FreePool (Private->ModeData);
    435 
    436 UninstallGopDevicePath:
    437   gBS->UninstallProtocolInterface (Private->Handle,
    438          &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
    439 
    440 FreeGopDevicePath:
    441   FreePool (Private->GopDevicePath);
    442 
    443 RestoreAttributes:
    444   Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,
    445                     Private->OriginalPciAttributes, NULL);
    446 
    447 ClosePciIo:
    448   gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
    449          This->DriverBindingHandle, Controller);
    450 
    451 FreePrivate:
    452   FreePool (Private);
    453 
    454 RestoreTpl:
    455   gBS->RestoreTPL (OldTpl);
    456 
    457   return Status;
    458 }
    459 
    460 /**
    461   Stop this device
    462 
    463   @param  This                   The USB bus driver binding protocol.
    464   @param  Controller             The controller to release.
    465   @param  NumberOfChildren       The number of children of this device that
    466                                  opened the controller BY_CHILD.
    467   @param  ChildHandleBuffer      The array of child handle.
    468 
    469   @retval EFI_SUCCESS            The controller or children are stopped.
    470   @retval EFI_DEVICE_ERROR       Failed to stop the driver.
    471 
    472 **/
    473 EFI_STATUS
    474 EFIAPI
    475 QemuVideoControllerDriverStop (
    476   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
    477   IN EFI_HANDLE                     Controller,
    478   IN UINTN                          NumberOfChildren,
    479   IN EFI_HANDLE                     *ChildHandleBuffer
    480   )
    481 {
    482   EFI_GRAPHICS_OUTPUT_PROTOCOL    *GraphicsOutput;
    483 
    484   EFI_STATUS                      Status;
    485   QEMU_VIDEO_PRIVATE_DATA  *Private;
    486 
    487   if (NumberOfChildren == 0) {
    488     //
    489     // Close the PCI I/O Protocol
    490     //
    491     gBS->CloseProtocol (
    492           Controller,
    493           &gEfiPciIoProtocolGuid,
    494           This->DriverBindingHandle,
    495           Controller
    496           );
    497     return EFI_SUCCESS;
    498   }
    499 
    500   //
    501   // free all resources for whose access we need the child handle, because the
    502   // child handle is going away
    503   //
    504   ASSERT (NumberOfChildren == 1);
    505   Status = gBS->OpenProtocol (
    506                   ChildHandleBuffer[0],
    507                   &gEfiGraphicsOutputProtocolGuid,
    508                   (VOID **) &GraphicsOutput,
    509                   This->DriverBindingHandle,
    510                   Controller,
    511                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    512                   );
    513   if (EFI_ERROR (Status)) {
    514     return Status;
    515   }
    516 
    517   //
    518   // Get our private context information
    519   //
    520   Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
    521   ASSERT (Private->Handle == ChildHandleBuffer[0]);
    522 
    523   QemuVideoGraphicsOutputDestructor (Private);
    524   //
    525   // Remove the GOP protocol interface from the system
    526   //
    527   Status = gBS->UninstallMultipleProtocolInterfaces (
    528                   Private->Handle,
    529                   &gEfiGraphicsOutputProtocolGuid,
    530                   &Private->GraphicsOutput,
    531                   NULL
    532                   );
    533 
    534   if (EFI_ERROR (Status)) {
    535     return Status;
    536   }
    537 
    538   //
    539   // Restore original PCI attributes
    540   //
    541   Private->PciIo->Attributes (
    542                   Private->PciIo,
    543                   EfiPciIoAttributeOperationSet,
    544                   Private->OriginalPciAttributes,
    545                   NULL
    546                   );
    547 
    548   gBS->CloseProtocol (
    549         Controller,
    550         &gEfiPciIoProtocolGuid,
    551         This->DriverBindingHandle,
    552         Private->Handle
    553         );
    554 
    555   FreePool (Private->ModeData);
    556   gBS->UninstallProtocolInterface (Private->Handle,
    557          &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
    558   FreePool (Private->GopDevicePath);
    559 
    560   //
    561   // Free our instance data
    562   //
    563   gBS->FreePool (Private);
    564 
    565   return EFI_SUCCESS;
    566 }
    567 
    568 /**
    569   TODO: Add function description
    570 
    571   @param  Private TODO: add argument description
    572   @param  Address TODO: add argument description
    573   @param  Data TODO: add argument description
    574 
    575   TODO: add return values
    576 
    577 **/
    578 VOID
    579 outb (
    580   QEMU_VIDEO_PRIVATE_DATA  *Private,
    581   UINTN                           Address,
    582   UINT8                           Data
    583   )
    584 {
    585   Private->PciIo->Io.Write (
    586                       Private->PciIo,
    587                       EfiPciIoWidthUint8,
    588                       EFI_PCI_IO_PASS_THROUGH_BAR,
    589                       Address,
    590                       1,
    591                       &Data
    592                       );
    593 }
    594 
    595 /**
    596   TODO: Add function description
    597 
    598   @param  Private TODO: add argument description
    599   @param  Address TODO: add argument description
    600   @param  Data TODO: add argument description
    601 
    602   TODO: add return values
    603 
    604 **/
    605 VOID
    606 outw (
    607   QEMU_VIDEO_PRIVATE_DATA  *Private,
    608   UINTN                           Address,
    609   UINT16                          Data
    610   )
    611 {
    612   Private->PciIo->Io.Write (
    613                       Private->PciIo,
    614                       EfiPciIoWidthUint16,
    615                       EFI_PCI_IO_PASS_THROUGH_BAR,
    616                       Address,
    617                       1,
    618                       &Data
    619                       );
    620 }
    621 
    622 /**
    623   TODO: Add function description
    624 
    625   @param  Private TODO: add argument description
    626   @param  Address TODO: add argument description
    627 
    628   TODO: add return values
    629 
    630 **/
    631 UINT8
    632 inb (
    633   QEMU_VIDEO_PRIVATE_DATA  *Private,
    634   UINTN                           Address
    635   )
    636 {
    637   UINT8 Data;
    638 
    639   Private->PciIo->Io.Read (
    640                       Private->PciIo,
    641                       EfiPciIoWidthUint8,
    642                       EFI_PCI_IO_PASS_THROUGH_BAR,
    643                       Address,
    644                       1,
    645                       &Data
    646                       );
    647   return Data;
    648 }
    649 
    650 /**
    651   TODO: Add function description
    652 
    653   @param  Private TODO: add argument description
    654   @param  Address TODO: add argument description
    655 
    656   TODO: add return values
    657 
    658 **/
    659 UINT16
    660 inw (
    661   QEMU_VIDEO_PRIVATE_DATA  *Private,
    662   UINTN                           Address
    663   )
    664 {
    665   UINT16  Data;
    666 
    667   Private->PciIo->Io.Read (
    668                       Private->PciIo,
    669                       EfiPciIoWidthUint16,
    670                       EFI_PCI_IO_PASS_THROUGH_BAR,
    671                       Address,
    672                       1,
    673                       &Data
    674                       );
    675   return Data;
    676 }
    677 
    678 /**
    679   TODO: Add function description
    680 
    681   @param  Private TODO: add argument description
    682   @param  Index TODO: add argument description
    683   @param  Red TODO: add argument description
    684   @param  Green TODO: add argument description
    685   @param  Blue TODO: add argument description
    686 
    687   TODO: add return values
    688 
    689 **/
    690 VOID
    691 SetPaletteColor (
    692   QEMU_VIDEO_PRIVATE_DATA  *Private,
    693   UINTN                           Index,
    694   UINT8                           Red,
    695   UINT8                           Green,
    696   UINT8                           Blue
    697   )
    698 {
    699   VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
    700   VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
    701   VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
    702   VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
    703 }
    704 
    705 /**
    706   TODO: Add function description
    707 
    708   @param  Private TODO: add argument description
    709 
    710   TODO: add return values
    711 
    712 **/
    713 VOID
    714 SetDefaultPalette (
    715   QEMU_VIDEO_PRIVATE_DATA  *Private
    716   )
    717 {
    718   UINTN Index;
    719   UINTN RedIndex;
    720   UINTN GreenIndex;
    721   UINTN BlueIndex;
    722 
    723   Index = 0;
    724   for (RedIndex = 0; RedIndex < 8; RedIndex++) {
    725     for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
    726       for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
    727         SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
    728         Index++;
    729       }
    730     }
    731   }
    732 }
    733 
    734 /**
    735   TODO: Add function description
    736 
    737   @param  Private TODO: add argument description
    738 
    739   TODO: add return values
    740 
    741 **/
    742 VOID
    743 ClearScreen (
    744   QEMU_VIDEO_PRIVATE_DATA  *Private
    745   )
    746 {
    747   UINT32  Color;
    748 
    749   Color = 0;
    750   Private->PciIo->Mem.Write (
    751                         Private->PciIo,
    752                         EfiPciIoWidthFillUint32,
    753                         0,
    754                         0,
    755                         0x400000 >> 2,
    756                         &Color
    757                         );
    758 }
    759 
    760 /**
    761   TODO: Add function description
    762 
    763   @param  Private TODO: add argument description
    764 
    765   TODO: add return values
    766 
    767 **/
    768 VOID
    769 DrawLogo (
    770   QEMU_VIDEO_PRIVATE_DATA  *Private,
    771   UINTN                           ScreenWidth,
    772   UINTN                           ScreenHeight
    773   )
    774 {
    775 }
    776 
    777 /**
    778   TODO: Add function description
    779 
    780   @param  Private TODO: add argument description
    781   @param  ModeData TODO: add argument description
    782 
    783   TODO: add return values
    784 
    785 **/
    786 VOID
    787 InitializeCirrusGraphicsMode (
    788   QEMU_VIDEO_PRIVATE_DATA  *Private,
    789   QEMU_VIDEO_CIRRUS_MODES  *ModeData
    790   )
    791 {
    792   UINT8 Byte;
    793   UINTN Index;
    794 
    795   outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
    796   outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
    797 
    798   for (Index = 0; Index < 15; Index++) {
    799     outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
    800   }
    801 
    802   if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
    803     outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
    804     Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
    805     outb (Private, SEQ_DATA_REGISTER, Byte);
    806   }
    807 
    808   outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
    809   outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
    810   outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
    811   outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
    812 
    813   for (Index = 0; Index < 28; Index++) {
    814     outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
    815   }
    816 
    817   for (Index = 0; Index < 9; Index++) {
    818     outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
    819   }
    820 
    821   inb (Private, INPUT_STATUS_1_REGISTER);
    822 
    823   for (Index = 0; Index < 21; Index++) {
    824     outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
    825     outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
    826   }
    827 
    828   outb (Private, ATT_ADDRESS_REGISTER, 0x20);
    829 
    830   outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
    831   outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
    832   outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
    833   outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
    834 
    835   SetDefaultPalette (Private);
    836   ClearScreen (Private);
    837 }
    838 
    839 VOID
    840 BochsWrite (
    841   QEMU_VIDEO_PRIVATE_DATA  *Private,
    842   UINT16                   Reg,
    843   UINT16                   Data
    844   )
    845 {
    846   EFI_STATUS   Status;
    847 
    848   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
    849     Status = Private->PciIo->Mem.Write (
    850         Private->PciIo,
    851         EfiPciIoWidthUint16,
    852         PCI_BAR_IDX2,
    853         0x500 + (Reg << 1),
    854         1,
    855         &Data
    856         );
    857     ASSERT_EFI_ERROR (Status);
    858   } else {
    859     outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
    860     outw (Private, VBE_DISPI_IOPORT_DATA,  Data);
    861   }
    862 }
    863 
    864 UINT16
    865 BochsRead (
    866   QEMU_VIDEO_PRIVATE_DATA  *Private,
    867   UINT16                   Reg
    868   )
    869 {
    870   EFI_STATUS   Status;
    871   UINT16       Data;
    872 
    873   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
    874     Status = Private->PciIo->Mem.Read (
    875         Private->PciIo,
    876         EfiPciIoWidthUint16,
    877         PCI_BAR_IDX2,
    878         0x500 + (Reg << 1),
    879         1,
    880         &Data
    881         );
    882     ASSERT_EFI_ERROR (Status);
    883   } else {
    884     outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
    885     Data = inw (Private, VBE_DISPI_IOPORT_DATA);
    886   }
    887   return Data;
    888 }
    889 
    890 VOID
    891 VgaOutb (
    892   QEMU_VIDEO_PRIVATE_DATA  *Private,
    893   UINTN                    Reg,
    894   UINT8                    Data
    895   )
    896 {
    897   EFI_STATUS   Status;
    898 
    899   if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
    900     Status = Private->PciIo->Mem.Write (
    901         Private->PciIo,
    902         EfiPciIoWidthUint8,
    903         PCI_BAR_IDX2,
    904         0x400 - 0x3c0 + Reg,
    905         1,
    906         &Data
    907         );
    908     ASSERT_EFI_ERROR (Status);
    909   } else {
    910     outb (Private, Reg, Data);
    911   }
    912 }
    913 
    914 VOID
    915 InitializeBochsGraphicsMode (
    916   QEMU_VIDEO_PRIVATE_DATA  *Private,
    917   QEMU_VIDEO_BOCHS_MODES  *ModeData
    918   )
    919 {
    920   DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
    921           ModeData->Width, ModeData->Height, ModeData->ColorDepth));
    922 
    923   /* unblank */
    924   VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
    925 
    926   BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,      0);
    927   BochsWrite (Private, VBE_DISPI_INDEX_BANK,        0);
    928   BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET,    0);
    929   BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET,    0);
    930 
    931   BochsWrite (Private, VBE_DISPI_INDEX_BPP,         (UINT16) ModeData->ColorDepth);
    932   BochsWrite (Private, VBE_DISPI_INDEX_XRES,        (UINT16) ModeData->Width);
    933   BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH,  (UINT16) ModeData->Width);
    934   BochsWrite (Private, VBE_DISPI_INDEX_YRES,        (UINT16) ModeData->Height);
    935   BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);
    936 
    937   BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,
    938               VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
    939 
    940   SetDefaultPalette (Private);
    941   ClearScreen (Private);
    942 }
    943 
    944 EFI_STATUS
    945 EFIAPI
    946 InitializeQemuVideo (
    947   IN EFI_HANDLE           ImageHandle,
    948   IN EFI_SYSTEM_TABLE     *SystemTable
    949   )
    950 {
    951   EFI_STATUS              Status;
    952 
    953   Status = EfiLibInstallDriverBindingComponentName2 (
    954              ImageHandle,
    955              SystemTable,
    956              &gQemuVideoDriverBinding,
    957              ImageHandle,
    958              &gQemuVideoComponentName,
    959              &gQemuVideoComponentName2
    960              );
    961   ASSERT_EFI_ERROR (Status);
    962 
    963   //
    964   // Install EFI Driver Supported EFI Version Protocol required for
    965   // EFI drivers that are on PCI and other plug in cards.
    966   //
    967   gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
    968   Status = gBS->InstallMultipleProtocolInterfaces (
    969                   &ImageHandle,
    970                   &gEfiDriverSupportedEfiVersionProtocolGuid,
    971                   &gQemuVideoDriverSupportedEfiVersion,
    972                   NULL
    973                   );
    974   ASSERT_EFI_ERROR (Status);
    975 
    976   return Status;
    977 }
    978