]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/QemuVideoDxe/Driver.c
OvmfPkg/QemuVideoDxe: child handles should have open parent protocol BY_CHILD_CONTROLLER
[mirror_edk2.git] / OvmfPkg / QemuVideoDxe / Driver.c
index cb3e34970dc0e1efe7f9d449230d150a1758ed8e..b253ec734edf9e214a916ad58930622f6a81124e 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
@@ -25,6 +26,55 @@ EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
   NULL\r
 };\r
 \r
+QEMU_VIDEO_CARD gQemuVideoCardList[] = {\r
+    {\r
+        CIRRUS_LOGIC_VENDOR_ID,\r
+        CIRRUS_LOGIC_5430_DEVICE_ID,\r
+        QEMU_VIDEO_CIRRUS_5430,\r
+        L"Cirrus 5430"\r
+    },{\r
+        CIRRUS_LOGIC_VENDOR_ID,\r
+        CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,\r
+        QEMU_VIDEO_CIRRUS_5430,\r
+        L"Cirrus 5430"\r
+    },{\r
+        CIRRUS_LOGIC_VENDOR_ID,\r
+        CIRRUS_LOGIC_5446_DEVICE_ID,\r
+        QEMU_VIDEO_CIRRUS_5446,\r
+        L"Cirrus 5446"\r
+    },{\r
+        0x1234,\r
+        0x1111,\r
+        QEMU_VIDEO_BOCHS_MMIO,\r
+        L"QEMU Standard VGA"\r
+    },{\r
+        0x1b36,\r
+        0x0100,\r
+        QEMU_VIDEO_BOCHS,\r
+        L"QEMU QXL VGA"\r
+    },{\r
+        0 /* end of list */\r
+    }\r
+};\r
+\r
+static QEMU_VIDEO_CARD*\r
+QemuVideoDetect(\r
+  IN UINT16 VendorId,\r
+  IN UINT16 DeviceId\r
+  )\r
+{\r
+  UINTN Index = 0;\r
+\r
+  while (gQemuVideoCardList[Index].VendorId != 0) {\r
+    if (gQemuVideoCardList[Index].VendorId == VendorId &&\r
+        gQemuVideoCardList[Index].DeviceId == DeviceId) {\r
+      return gQemuVideoCardList + Index;\r
+    }\r
+    Index++;\r
+  }\r
+  return NULL;\r
+}\r
+\r
 /**\r
   Check if this device is supported.\r
 \r
@@ -48,6 +98,7 @@ QemuVideoControllerDriverSupported (
   EFI_PCI_IO_PROTOCOL *PciIo;\r
   PCI_TYPE00          Pci;\r
   EFI_DEV_PATH        *Node;\r
+  QEMU_VIDEO_CARD     *Card;\r
 \r
   //\r
   // Open the PCI I/O Protocol\r
@@ -87,35 +138,29 @@ QemuVideoControllerDriverSupported (
   //\r
   // See if this is a Cirrus Logic PCI controller\r
   //\r
-  if (Pci.Hdr.VendorId == CIRRUS_LOGIC_VENDOR_ID) {\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
-    // See if this is a 5430 or a 5446 PCI controller\r
+    // If this is an Intel 945 graphics controller,\r
+    // go further check RemainingDevicePath validation\r
     //\r
-    if (Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_DEVICE_ID || \r
-        Pci.Hdr.DeviceId == CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID ||\r
-        Pci.Hdr.DeviceId == CIRRUS_LOGIC_5446_DEVICE_ID) {\r
-        \r
-      Status = EFI_SUCCESS;\r
+    if (RemainingDevicePath != NULL) {\r
+      Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
       //\r
-      // If this is an Intel 945 graphics controller,\r
-      // go further check RemainingDevicePath validation\r
+      // Check if RemainingDevicePath is the End of Device Path Node, \r
+      // if yes, return EFI_SUCCESS\r
       //\r
-      if (RemainingDevicePath != NULL) {\r
-        Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+      if (!IsDevicePathEnd (Node)) {\r
         //\r
-        // Check if RemainingDevicePath is the End of Device Path Node, \r
-        // if yes, return EFI_SUCCESS\r
+        // If RemainingDevicePath isn't the End of Device Path Node,\r
+        // check its validation\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
+        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
@@ -156,11 +201,15 @@ 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
+  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_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;\r
+  EFI_PCI_IO_PROTOCOL               *ChildPciIo;\r
 \r
   PciAttributesSaved = FALSE;\r
   //\r
@@ -193,6 +242,27 @@ QemuVideoControllerDriverStart (
     goto Error;\r
   }\r
 \r
+  //\r
+  // Read the PCI Configuration Header from the PCI Device\r
+  //\r
+  Status = Private->PciIo->Pci.Read (\r
+                        Private->PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        0,\r
+                        sizeof (Pci) / sizeof (UINT32),\r
+                        &Pci\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);\r
+  if (Card == NULL) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Error;\r
+  }\r
+  Private->Variant = Card->Variant;\r
+\r
   //\r
   // Save original PCI attributes\r
   //\r
@@ -218,6 +288,44 @@ QemuVideoControllerDriverStart (
     goto Error;\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
+    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_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
+    }\r
+  }\r
+\r
   //\r
   // Get ParentDevicePath\r
   //\r
@@ -274,7 +382,20 @@ QemuVideoControllerDriverStart (
   //\r
   // Construct video mode buffer\r
   //\r
-  Status = QemuVideoVideoModeSetup (Private);\r
+  switch (Private->Variant) {\r
+  case QEMU_VIDEO_CIRRUS_5430:\r
+  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
+  default:\r
+    ASSERT (FALSE);\r
+    Status = EFI_DEVICE_ERROR;\r
+    break;\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     goto Error;\r
   }\r
@@ -299,6 +420,22 @@ QemuVideoControllerDriverStart (
                     &Private->GraphicsOutput,\r
                     NULL\r
                     );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\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
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
   }\r
 \r
 Error:\r
@@ -320,7 +457,14 @@ Error:
         // Close the PCI I/O Protocol\r
         //\r
         gBS->CloseProtocol (\r
-              Private->Handle,\r
+              Controller,\r
+              &gEfiPciIoProtocolGuid,\r
+              This->DriverBindingHandle,\r
+              Controller\r
+              );\r
+\r
+        gBS->CloseProtocol (\r
+              Controller,\r
               &gEfiPciIoProtocolGuid,\r
               This->DriverBindingHandle,\r
               Private->Handle\r
@@ -413,6 +557,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
@@ -552,10 +703,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
@@ -640,27 +791,13 @@ DrawLogo (
 \r
 **/\r
 VOID\r
-InitializeGraphicsMode (\r
+InitializeCirrusGraphicsMode (\r
   QEMU_VIDEO_PRIVATE_DATA  *Private,\r
-  QEMU_VIDEO_VIDEO_MODES   *ModeData\r
+  QEMU_VIDEO_CIRRUS_MODES  *ModeData\r
   )\r
 {\r
   UINT8 Byte;\r
   UINTN Index;\r
-  UINT16 DeviceId;\r
-  EFI_STATUS Status;\r
-\r
-  Status = Private->PciIo->Pci.Read (\r
-             Private->PciIo,\r
-             EfiPciIoWidthUint16,\r
-             PCI_DEVICE_ID_OFFSET,\r
-             1,\r
-             &DeviceId\r
-             );\r
-  //\r
-  // Read the PCI Configuration Header from the PCI Device\r
-  //\r
-  ASSERT_EFI_ERROR (Status);\r
 \r
   outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);\r
   outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);\r
@@ -669,7 +806,7 @@ InitializeGraphicsMode (
     outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);\r
   }\r
 \r
-  if (DeviceId != CIRRUS_LOGIC_5446_DEVICE_ID) {\r
+  if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {\r
     outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);\r
     Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);\r
     outb (Private, SEQ_DATA_REGISTER, Byte);\r
@@ -706,6 +843,111 @@ InitializeGraphicsMode (
   ClearScreen (Private);\r
 }\r
 \r
+VOID\r
+BochsWrite (\r
+  QEMU_VIDEO_PRIVATE_DATA  *Private,\r
+  UINT16                   Reg,\r
+  UINT16                   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
+        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
+BochsRead (\r
+  QEMU_VIDEO_PRIVATE_DATA  *Private,\r
+  UINT16                   Reg\r
+  )\r
+{\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
+  QEMU_VIDEO_BOCHS_MODES  *ModeData\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",\r
+          ModeData->Width, ModeData->Height, ModeData->ColorDepth));\r
+\r
+  /* unblank */\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
+  BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET,    0);\r
+  BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET,    0);\r
+\r
+  BochsWrite (Private, VBE_DISPI_INDEX_BPP,         (UINT16) ModeData->ColorDepth);\r
+  BochsWrite (Private, VBE_DISPI_INDEX_XRES,        (UINT16) ModeData->Width);\r
+  BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH,  (UINT16) ModeData->Width);\r
+  BochsWrite (Private, VBE_DISPI_INDEX_YRES,        (UINT16) ModeData->Height);\r
+  BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);\r
+\r
+  BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,\r
+              VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);\r
+\r
+  SetDefaultPalette (Private);\r
+  ClearScreen (Private);\r
+}\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 InitializeQemuVideo (\r