]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg: QemuVideoDxe: simplify UEFI driver model use in Supported() / Start()
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
index 04f73f3ba1d335a06cba3ead8a87855da829269b..508e1acb1018becf6715400f0677857c0c1b8e2f 100644 (file)
@@ -15,6 +15,7 @@
 **/\r
 \r
 #include "Qemu.h"\r
+#include <IndustryStandard/Acpi.h>\r
 \r
 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {\r
   QemuVideoControllerDriverSupported,\r
@@ -44,7 +45,7 @@ QEMU_VIDEO_CARD gQemuVideoCardList[] = {
     },{\r
         0x1234,\r
         0x1111,\r
-        QEMU_VIDEO_BOCHS,\r
+        QEMU_VIDEO_BOCHS_MMIO,\r
         L"QEMU Standard VGA"\r
     },{\r
         0x1b36,\r
@@ -96,7 +97,6 @@ QemuVideoControllerDriverSupported (
   EFI_STATUS          Status;\r
   EFI_PCI_IO_PROTOCOL *PciIo;\r
   PCI_TYPE00          Pci;\r
-  EFI_DEV_PATH        *Node;\r
   QEMU_VIDEO_CARD     *Card;\r
 \r
   //\r
@@ -129,40 +129,10 @@ QemuVideoControllerDriverSupported (
   }\r
 \r
   Status = EFI_UNSUPPORTED;\r
-  //\r
-  // See if the I/O enable is on.  Most systems only allow one VGA device to be turned on\r
-  // at a time, so see if this is one that is turned on.\r
-  //\r
-  //  if (((Pci.Hdr.Command & 0x01) == 0x01)) {\r
-  //\r
-  // See if this is a Cirrus Logic PCI controller\r
-  //\r
   Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
   if (Card != NULL) {\r
     DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));\r
     Status = EFI_SUCCESS;\r
-    //\r
-    // If this is an Intel 945 graphics controller,\r
-    // go further check RemainingDevicePath validation\r
-    //\r
-    if (RemainingDevicePath != NULL) {\r
-      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
-      //\r
-      // Check if RemainingDevicePath is the End of Device Path Node, \r
-      // if yes, return EFI_SUCCESS\r
-      //\r
-      if (!IsDevicePathEnd (Node)) {\r
-        //\r
-        // If RemainingDevicePath isn't the End of Device Path Node,\r
-        // check its validation\r
-        //\r
-        if (Node->DevPath.Type != ACPI_DEVICE_PATH ||\r
-            Node->DevPath.SubType != ACPI_ADR_DP ||\r
-            DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {\r
-          Status = EFI_UNSUPPORTED;\r
-        }\r
-      }\r
-    }\r
   }\r
 \r
 Done:\r
@@ -200,29 +170,26 @@ QemuVideoControllerDriverStart (
   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath\r
   )\r
 {\r
-  EFI_STATUS                      Status;\r
-  QEMU_VIDEO_PRIVATE_DATA  *Private;\r
-  BOOLEAN                         PciAttributesSaved;\r
-  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;\r
-  ACPI_ADR_DEVICE_PATH            AcpiDeviceNode;\r
-  PCI_TYPE00                      Pci;\r
-  QEMU_VIDEO_CARD                 *Card;\r
+  EFI_STATUS                        Status;\r
+  QEMU_VIDEO_PRIVATE_DATA           *Private;\r
+  EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;\r
+  ACPI_ADR_DEVICE_PATH              AcpiDeviceNode;\r
+  PCI_TYPE00                        Pci;\r
+  QEMU_VIDEO_CARD                   *Card;\r
+  EFI_PCI_IO_PROTOCOL               *ChildPciIo;\r
 \r
-  PciAttributesSaved = FALSE;\r
   //\r
   // Allocate Private context data for GOP inteface.\r
   //\r
   Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));\r
   if (Private == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto Error;\r
+    return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   //\r
   // Set up context record\r
   //\r
   Private->Signature  = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;\r
-  Private->Handle     = NULL;\r
 \r
   //\r
   // Open PCI I/O Protocol\r
@@ -236,7 +203,7 @@ QemuVideoControllerDriverStart (
                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto FreePrivate;\r
   }\r
 \r
   //\r
@@ -250,13 +217,16 @@ QemuVideoControllerDriverStart (
                         &Pci\r
                         );\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto ClosePciIo;\r
   }\r
 \r
+  //\r
+  // Determine card variant.\r
+  //\r
   Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
   if (Card == NULL) {\r
     Status = EFI_DEVICE_ERROR;\r
-    goto Error;\r
+    goto ClosePciIo;\r
   }\r
   Private->Variant = Card->Variant;\r
 \r
@@ -271,10 +241,12 @@ QemuVideoControllerDriverStart (
                     );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto ClosePciIo;\r
   }\r
-  PciAttributesSaved = TRUE;\r
 \r
+  //\r
+  // Set new PCI attributes\r
+  //\r
   Status = Private->PciIo->Attributes (\r
                             Private->PciIo,\r
                             EfiPciIoAttributeOperationEnable,\r
@@ -282,19 +254,46 @@ QemuVideoControllerDriverStart (
                             NULL\r
                             );\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto ClosePciIo;\r
+  }\r
+\r
+  //\r
+  // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).\r
+  //\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
+    EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;\r
+\r
+    Status = Private->PciIo->GetBarAttributes (\r
+                        Private->PciIo,\r
+                        PCI_BAR_IDX2,\r
+                        NULL,\r
+                        (VOID**) &MmioDesc\r
+                        );\r
+    if (EFI_ERROR (Status) ||\r
+        MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
+      DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));\r
+      Private->Variant = QEMU_VIDEO_BOCHS;\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",\r
+              MmioDesc->AddrRangeMin));\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      FreePool (MmioDesc);\r
+    }\r
   }\r
 \r
   //\r
   // Check if accessing the bochs interface works.\r
   //\r
-  if (Private->Variant == QEMU_VIDEO_BOCHS) {\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||\r
+      Private->Variant == QEMU_VIDEO_BOCHS) {\r
     UINT16 BochsId;\r
     BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);\r
     if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {\r
       DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));\r
       Status = EFI_DEVICE_ERROR;\r
-      goto Error;\r
+      goto RestoreAttributes;\r
     }\r
   }\r
 \r
@@ -307,48 +306,38 @@ QemuVideoControllerDriverStart (
                   (VOID **) &ParentDevicePath\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto RestoreAttributes;\r
   }\r
 \r
   //\r
   // Set Gop Device Path\r
   //\r
-  if (RemainingDevicePath == NULL) {\r
-    ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
-    AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
-    AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
-    AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
-    SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
-\r
-    Private->GopDevicePath = AppendDevicePathNode (\r
-                                        ParentDevicePath,\r
-                                        (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
-                                        );\r
-  } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
-    //\r
-    // If RemainingDevicePath isn't the End of Device Path Node, \r
-    // only scan the specified device by RemainingDevicePath\r
-    //\r
-    Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);\r
-  } else {\r
-    //\r
-    // If RemainingDevicePath is the End of Device Path Node, \r
-    // don't create child device and return EFI_SUCCESS\r
-    //\r
-    Private->GopDevicePath = NULL;\r
+  ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));\r
+  AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;\r
+  AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;\r
+  AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);\r
+  SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));\r
+\r
+  Private->GopDevicePath = AppendDevicePathNode (\r
+                                      ParentDevicePath,\r
+                                      (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode\r
+                                      );\r
+  if (Private->GopDevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto RestoreAttributes;\r
   }\r
-    \r
-  if (Private->GopDevicePath != NULL) {\r
-    //\r
-    // Creat child handle and device path protocol firstly\r
-    //\r
-    Private->Handle = NULL;\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &Private->Handle,\r
-                    &gEfiDevicePathProtocolGuid,\r
-                    Private->GopDevicePath,\r
-                    NULL\r
-                    );\r
+\r
+  //\r
+  // Create new child handle and install the device path protocol on it.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Private->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  Private->GopDevicePath,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeGopDevicePath;\r
   }\r
 \r
   //\r
@@ -359,6 +348,7 @@ QemuVideoControllerDriverStart (
   case QEMU_VIDEO_CIRRUS_5446:\r
     Status = QemuVideoCirrusModeSetup (Private);\r
     break;\r
+  case QEMU_VIDEO_BOCHS_MMIO:\r
   case QEMU_VIDEO_BOCHS:\r
     Status = QemuVideoBochsModeSetup (Private);\r
     break;\r
@@ -368,61 +358,72 @@ QemuVideoControllerDriverStart (
     break;\r
   }\r
   if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+    goto UninstallGopDevicePath;\r
   }\r
 \r
-  if (Private->GopDevicePath == NULL) {\r
-    //\r
-    // If RemainingDevicePath is the End of Device Path Node, \r
-    // don't create child device and return EFI_SUCCESS\r
-    //\r
-    Status = EFI_SUCCESS;\r
-  } else {\r
-\r
-    //\r
-    // Start the GOP software stack.\r
-    //\r
-    Status = QemuVideoGraphicsOutputConstructor (Private);\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    Status = gBS->InstallMultipleProtocolInterfaces (\r
-                    &Private->Handle,\r
-                    &gEfiGraphicsOutputProtocolGuid,\r
-                    &Private->GraphicsOutput,\r
-                    NULL\r
-                    );\r
+  //\r
+  // Start the GOP software stack.\r
+  //\r
+  Status = QemuVideoGraphicsOutputConstructor (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    goto FreeModeData;\r
   }\r
 \r
-Error:\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Private->Handle,\r
+                  &gEfiGraphicsOutputProtocolGuid,\r
+                  &Private->GraphicsOutput,\r
+                  NULL\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
-    if (Private) {\r
-      if (Private->PciIo) {\r
-        if (PciAttributesSaved == TRUE) {\r
-          //\r
-          // Restore original PCI attributes\r
-          //\r
-          Private->PciIo->Attributes (\r
-                          Private->PciIo,\r
-                          EfiPciIoAttributeOperationSet,\r
-                          Private->OriginalPciAttributes,\r
-                          NULL\r
-                          );\r
-        }\r
-        //\r
-        // Close the PCI I/O Protocol\r
-        //\r
-        gBS->CloseProtocol (\r
-              Private->Handle,\r
-              &gEfiPciIoProtocolGuid,\r
-              This->DriverBindingHandle,\r
-              Private->Handle\r
-              );\r
-      }\r
+    goto DestructQemuVideoGraphics;\r
+  }\r
 \r
-      gBS->FreePool (Private);\r
-    }\r
+  //\r
+  // Reference parent handle from child handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                Controller,\r
+                &gEfiPciIoProtocolGuid,\r
+                (VOID **) &ChildPciIo,\r
+                This->DriverBindingHandle,\r
+                Private->Handle,\r
+                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+                );\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninstallGop;\r
   }\r
 \r
+  return EFI_SUCCESS;\r
+\r
+UninstallGop:\r
+  gBS->UninstallProtocolInterface (Private->Handle,\r
+         &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);\r
+\r
+DestructQemuVideoGraphics:\r
+  QemuVideoGraphicsOutputDestructor (Private);\r
+\r
+FreeModeData:\r
+  FreePool (Private->ModeData);\r
+\r
+UninstallGopDevicePath:\r
+  gBS->UninstallProtocolInterface (Private->Handle,\r
+         &gEfiDevicePathProtocolGuid, Private->GopDevicePath);\r
+\r
+FreeGopDevicePath:\r
+  FreePool (Private->GopDevicePath);\r
+\r
+RestoreAttributes:\r
+  Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,\r
+                    Private->OriginalPciAttributes, NULL);\r
+\r
+ClosePciIo:\r
+  gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle, Controller);\r
+\r
+FreePrivate:\r
+  FreePool (Private);\r
+\r
   return Status;\r
 }\r
 \r
@@ -505,6 +506,13 @@ QemuVideoControllerDriverStop (
         Controller\r
         );\r
 \r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Private->Handle\r
+        );\r
+\r
   //\r
   // Free our instance data\r
   //\r
@@ -644,10 +652,10 @@ SetPaletteColor (
   UINT8                           Blue\r
   )\r
 {\r
-  outb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);\r
-  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));\r
-  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));\r
-  outb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));\r
+  VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);\r
+  VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));\r
+  VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));\r
+  VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));\r
 }\r
 \r
 /**\r
@@ -791,8 +799,22 @@ BochsWrite (
   UINT16                   Data\r
   )\r
 {\r
-  outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
-  outw (Private, VBE_DISPI_IOPORT_DATA,  Data);\r
+  EFI_STATUS   Status;\r
+\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
+    Status = Private->PciIo->Mem.Write (\r
+        Private->PciIo,\r
+        EfiPciIoWidthUint16,\r
+        PCI_BAR_IDX2,\r
+        0x500 + (Reg << 1),\r
+        1,\r
+        &Data\r
+        );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
+    outw (Private, VBE_DISPI_IOPORT_DATA,  Data);\r
+  }\r
 }\r
 \r
 UINT16\r
@@ -801,13 +823,50 @@ BochsRead (
   UINT16                   Reg\r
   )\r
 {\r
-  UINT16 Data;\r
-\r
-  outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
-  Data = inw (Private, VBE_DISPI_IOPORT_DATA);\r
+  EFI_STATUS   Status;\r
+  UINT16       Data;\r
+\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
+    Status = Private->PciIo->Mem.Read (\r
+        Private->PciIo,\r
+        EfiPciIoWidthUint16,\r
+        PCI_BAR_IDX2,\r
+        0x500 + (Reg << 1),\r
+        1,\r
+        &Data\r
+        );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);\r
+    Data = inw (Private, VBE_DISPI_IOPORT_DATA);\r
+  }\r
   return Data;\r
 }\r
 \r
+VOID\r
+VgaOutb (\r
+  QEMU_VIDEO_PRIVATE_DATA  *Private,\r
+  UINTN                    Reg,\r
+  UINT8                    Data\r
+  )\r
+{\r
+  EFI_STATUS   Status;\r
+\r
+  if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {\r
+    Status = Private->PciIo->Mem.Write (\r
+        Private->PciIo,\r
+        EfiPciIoWidthUint8,\r
+        PCI_BAR_IDX2,\r
+        0x400 - 0x3c0 + Reg,\r
+        1,\r
+        &Data\r
+        );\r
+    ASSERT_EFI_ERROR (Status);\r
+  } else {\r
+    outb (Private, Reg, Data);\r
+  }\r
+}\r
+\r
 VOID\r
 InitializeBochsGraphicsMode (\r
   QEMU_VIDEO_PRIVATE_DATA  *Private,\r
@@ -818,7 +877,7 @@ InitializeBochsGraphicsMode (
           ModeData->Width, ModeData->Height, ModeData->ColorDepth));\r
 \r
   /* unblank */\r
-  outb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
+  VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);\r
 \r
   BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,      0);\r
   BochsWrite (Private, VBE_DISPI_INDEX_BANK,        0);\r