UEFI Framework - 3 [ EFI Driver Model ] Sample code

因為在 EFI Driver Model 這篇文章中有提到了一些概念
但是基於自己還有些模糊的情況下
就找了些Sample Code來強化自己的觀念

使用上會有四個Step

  1. Initialize:安裝Driver Binding Protocol
  2. Support():詢問可不可以支援傳入的Handle
  3. Start():連結Device 及 Handle
  4. Stop():斷開Device 及 Handle

在設計上要注意到以下幾點
  1. 符合EFU Model的規範
  2. 保持Support函式的輕巧,複雜的I/O工作在Start()的時後再做

EDK的Sample 中有個VgaMainPort.c

Initialize:安裝Driver Binding Protocol
EFI_DRIVER_BINDING_PROTOCOL gPciVgaMiniPortDriverBinding = {
  PciVgaMiniPortDriverBindingSupported,
  PciVgaMiniPortDriverBindingStart,
  PciVgaMiniPortDriverBindingStop,
  0x00000000,
  NULL,
  NULL
};

/**
  Entrypoint of VGA Mini Port Driver.

  This function is the entrypoint of UVGA Mini Port Driver. It installs Driver Binding
  Protocols together with Component Name Protocols.

  @param  ImageHandle       The firmware allocated handle for the EFI image.
  @param  SystemTable       A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.

**/
FI_STATUS EFIAPI
PciVgaMiniPortDriverEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
{
  EFI_STATUS              Status;

  Status = EfiLibInstallDriverBindingComponentName2 (
             ImageHandle,
             SystemTable,
             &gPciVgaMiniPortDriverBinding,
             ImageHandle,
             &gPciVgaMiniPortComponentName,
             &gPciVgaMiniPortComponentName2
             );
  ASSERT_EFI_ERROR (Status);

  return EFI_SUCCESS;
}



Support():詢問可不可以支援傳入的Handle
/**
  Check whether VGA Mini Port driver supports this device.

  @param  This                   The driver binding protocol.
  @param  Controller             The controller handle to check.
  @param  RemainingDevicePath    The remaining device path.

  @retval EFI_SUCCESS            The driver supports this controller.
  @retval EFI_UNSUPPORTED        This device isn't supported.

**/
EFI_STATUS
EFIAPI
PciVgaMiniPortDriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS          Status;
  EFI_PCI_IO_PROTOCOL *PciIo;
  PCI_TYPE00          Pci;

  //
  // Open the IO Abstraction(s) needed to perform the supported test
  //
  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiPciIoProtocolGuid,
                  (VOID **) &PciIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }
  //
  // See if this is a PCI VGA Controller by looking at the Command register and
  // Class Code Register
  //
  Status = PciIo->Pci.Read (
                        PciIo,
                        EfiPciIoWidthUint32,
                        0,
                        sizeof (Pci) / sizeof (UINT32),
                        &Pci
                        );
  if (EFI_ERROR (Status)) {
    goto Done;
  }

  Status = EFI_UNSUPPORTED;
  //
  // See if the device is an enabled VGA device.
  // Most systems can only have on VGA device on at a time.
  //
  if (((Pci.Hdr.Command & 0x03) == 0x03) && IS_PCI_VGA (&Pci)) {
    Status = EFI_SUCCESS;
  }

Done:
  gBS->CloseProtocol (
         Controller,
         &gEfiPciIoProtocolGuid,
         This->DriverBindingHandle,
         Controller
         );

  return Status;
}





Start():連結Device 及 Handle
/**
  Starts the VGA device with this driver.

  This function consumes PCI I/O Protocol, and installs VGA Mini Port Protocol
  onto the VGA device handle.

  @param  This                   The driver binding instance.
  @param  Controller             The controller to check.
  @param  RemainingDevicePath    The remaining device patch.

  @retval EFI_SUCCESS            The controller is controlled by the driver.
  @retval EFI_ALREADY_STARTED    The controller is already controlled by the driver.
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources.

**/
EFI_STATUS
EFIAPI
PciVgaMiniPortDriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS            Status;
  EFI_PCI_IO_PROTOCOL   *PciIo;
  PCI_VGA_MINI_PORT_DEV *PciVgaMiniPortPrivate;

  PciVgaMiniPortPrivate = NULL;
  PciIo                 = NULL;
  //
  // Open the IO Abstraction(s) needed
  //
  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiPciIoProtocolGuid,
                  (VOID **) &PciIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    goto Done;
  }
  //
  // Allocate the private device structure
  //
  PciVgaMiniPortPrivate = AllocateZeroPool (sizeof (PCI_VGA_MINI_PORT_DEV));
  ASSERT (PciVgaMiniPortPrivate != NULL);

  //
  // Initialize the private device structure
  //
  PciVgaMiniPortPrivate->Signature = PCI_VGA_MINI_PORT_DEV_SIGNATURE;
  PciVgaMiniPortPrivate->Handle = Controller;
  PciVgaMiniPortPrivate->PciIo = PciIo;

  PciVgaMiniPortPrivate->VgaMiniPort.SetMode = PciVgaMiniPortSetMode;
  PciVgaMiniPortPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
  PciVgaMiniPortPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
  PciVgaMiniPortPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
  PciVgaMiniPortPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
  PciVgaMiniPortPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
  PciVgaMiniPortPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
  PciVgaMiniPortPrivate->VgaMiniPort.MaxMode = 1;

  //
  // Install VGA Mini Port Protocol
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Controller,
                  &gEfiVgaMiniPortProtocolGuid,
                  &PciVgaMiniPortPrivate->VgaMiniPort,
                  NULL
                  );
Done:
  if (EFI_ERROR (Status)) {
    gBS->CloseProtocol (
           Controller,
           &gEfiPciIoProtocolGuid,
           This->DriverBindingHandle,
           Controller
           );
    if (PciVgaMiniPortPrivate != NULL) {
      FreePool (PciVgaMiniPortPrivate);
    }
  }

  return Status;
}




Stop():斷開Device 及 Handle
/**
  Stop the VGA device with this driver.

  This function uninstalls VGA Mini Port Protocol from the VGA device handle,
  and closes PCI I/O Protocol.

  @param  This                   The driver binding protocol.
  @param  Controller             The controller to release.
  @param  NumberOfChildren       The child number that opened controller
                                 BY_CHILD.
  @param  ChildHandleBuffer      The array of child handle.

  @retval EFI_SUCCESS            The controller or children are stopped.
  @retval EFI_DEVICE_ERROR       Failed to stop the driver.

**/
EFI_STATUS
EFIAPI
PciVgaMiniPortDriverBindingStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
  IN  EFI_HANDLE                      Controller,
  IN  UINTN                           NumberOfChildren,
  IN  EFI_HANDLE                      *ChildHandleBuffer
  )
{
  EFI_STATUS                  Status;
  EFI_VGA_MINI_PORT_PROTOCOL  *VgaMiniPort;
  PCI_VGA_MINI_PORT_DEV       *PciVgaMiniPortPrivate;

  Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiVgaMiniPortProtocolGuid,
                  (VOID **) &VgaMiniPort,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  PciVgaMiniPortPrivate = PCI_VGA_MINI_PORT_DEV_FROM_THIS (VgaMiniPort);

  Status = gBS->UninstallProtocolInterface (
                  Controller,
                  &gEfiVgaMiniPortProtocolGuid,
                  &PciVgaMiniPortPrivate->VgaMiniPort
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  gBS->CloseProtocol (
         Controller,
         &gEfiPciIoProtocolGuid,
         This->DriverBindingHandle,
         Controller
         );

  FreePool (PciVgaMiniPortPrivate);

  return EFI_SUCCESS;
}


留言