| /** @file | |
| EFI glue for BIOS INT 13h block devices. | |
| This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4 | |
| Availible on http://www.t13.org/#Project drafts | |
| Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf | |
| Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions | |
| of the BSD License which accompanies this distribution. The | |
| full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "BiosBlkIo.h" | |
| // | |
| // Global data declaration | |
| // | |
| // | |
| // EFI Driver Binding Protocol Instance | |
| // | |
| EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = { | |
| BiosBlockIoDriverBindingSupported, | |
| BiosBlockIoDriverBindingStart, | |
| BiosBlockIoDriverBindingStop, | |
| 0x3, | |
| NULL, | |
| NULL | |
| }; | |
| // | |
| // Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb | |
| // | |
| EFI_LOCK mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION); | |
| // | |
| // Number of active instances of this protocol. This is used to allocate/free | |
| // the shared buffer. You must acquire the semaphore to modify. | |
| // | |
| UINTN mActiveInstances = 0; | |
| // | |
| // Pointer to the beginning of the buffer used for real mode thunk | |
| // You must acquire the semaphore to modify. | |
| // | |
| EFI_PHYSICAL_ADDRESS mBufferUnder1Mb = 0; | |
| // | |
| // Address packet is a buffer under 1 MB for all version EDD calls | |
| // | |
| EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb; | |
| // | |
| // This is a buffer for INT 13h func 48 information | |
| // | |
| BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb; | |
| // | |
| // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB | |
| // 0xFE00 bytes is the max transfer size supported. | |
| // | |
| VOID *mEdd11Buffer; | |
| /** | |
| Driver entry point. | |
| @param ImageHandle Handle of driver image. | |
| @param SystemTable Pointer to system table. | |
| @retval EFI_SUCCESS Entrypoint successfully executed. | |
| @retval Others Fail to execute entrypoint. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosBlockIoDriverEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Install protocols | |
| // | |
| Status = EfiLibInstallDriverBindingComponentName2 ( | |
| ImageHandle, | |
| SystemTable, | |
| &gBiosBlockIoDriverBinding, | |
| ImageHandle, | |
| &gBiosBlockIoComponentName, | |
| &gBiosBlockIoComponentName2 | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver | |
| // | |
| return gBS->InstallMultipleProtocolInterfaces ( | |
| &ImageHandle, | |
| &gEfiLegacyBiosGuid, | |
| NULL, | |
| NULL | |
| ); | |
| } | |
| /** | |
| Check whether the driver supports this device. | |
| @param This The Udriver binding protocol. | |
| @param Controller The controller handle to check. | |
| @param RemainingDevicePath The remaining device path. | |
| @retval EFI_SUCCESS The driver supports this controller. | |
| @retval other This device isn't supported. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosBlockIoDriverBindingSupported ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| PCI_TYPE00 Pci; | |
| // | |
| // See if the Legacy BIOS Protocol is available | |
| // | |
| Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &DevicePath, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| // | |
| // 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)) { | |
| Status = EFI_UNSUPPORTED; | |
| goto Done; | |
| } | |
| Status = EFI_UNSUPPORTED; | |
| if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE || | |
| (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT) | |
| ) { | |
| Status = EFI_SUCCESS; | |
| } | |
| Done: | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Starts the device with this driver. | |
| @param This The driver binding instance. | |
| @param Controller Handle of device to bind driver to. | |
| @param RemainingDevicePath Optional parameter use to pick a specific child | |
| device to start. | |
| @retval EFI_SUCCESS The controller is controlled by the driver. | |
| @retval Other This controller cannot be started. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosBlockIoDriverBindingStart ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT8 DiskStart; | |
| UINT8 DiskEnd; | |
| BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate; | |
| EFI_DEVICE_PATH_PROTOCOL *PciDevPath; | |
| UINTN Index; | |
| UINTN Flags; | |
| UINTN TmpAddress; | |
| BOOLEAN DeviceEnable; | |
| // | |
| // Initialize variables | |
| // | |
| PciIo = NULL; | |
| PciDevPath = NULL; | |
| DeviceEnable = FALSE; | |
| // | |
| // See if the Legacy BIOS Protocol is available | |
| // | |
| Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| // | |
| // 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 Error; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID **) &PciDevPath, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| // | |
| // Enable the device and make sure VGA cycles are being forwarded to this VGA device | |
| // | |
| Status = PciIo->Attributes ( | |
| PciIo, | |
| EfiPciIoAttributeOperationEnable, | |
| EFI_PCI_DEVICE_ENABLE, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| DeviceEnable = TRUE; | |
| // | |
| // Check to see if there is a legacy option ROM image associated with this PCI device | |
| // | |
| Status = LegacyBios->CheckPciRom ( | |
| LegacyBios, | |
| Controller, | |
| NULL, | |
| NULL, | |
| &Flags | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| // | |
| // Post the legacy option ROM if it is available. | |
| // | |
| Status = LegacyBios->InstallPciRom ( | |
| LegacyBios, | |
| Controller, | |
| NULL, | |
| &Flags, | |
| &DiskStart, | |
| &DiskEnd, | |
| NULL, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| // | |
| // All instances share a buffer under 1MB to put real mode thunk code in | |
| // If it has not been allocated, then we allocate it. | |
| // | |
| if (mBufferUnder1Mb == 0) { | |
| // | |
| // Should only be here if there are no active instances | |
| // | |
| ASSERT (mActiveInstances == 0); | |
| // | |
| // Acquire the lock | |
| // | |
| EfiAcquireLock (&mGlobalDataLock); | |
| // | |
| // Allocate below 1MB | |
| // | |
| mBufferUnder1Mb = 0x00000000000FFFFF; | |
| Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb); | |
| // | |
| // Release the lock | |
| // | |
| EfiReleaseLock (&mGlobalDataLock); | |
| // | |
| // Check memory allocation success | |
| // | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // In checked builds we want to assert if the allocate failed. | |
| // | |
| ASSERT_EFI_ERROR (Status); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| mBufferUnder1Mb = 0; | |
| goto Error; | |
| } | |
| TmpAddress = (UINTN) mBufferUnder1Mb; | |
| // | |
| // Adjusting the value to be on proper boundary | |
| // | |
| mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress); | |
| TmpAddress = (UINTN) mEdd11Buffer + MAX_EDD11_XFER; | |
| // | |
| // Adjusting the value to be on proper boundary | |
| // | |
| mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress); | |
| TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE); | |
| // | |
| // Adjusting the value to be on proper boundary | |
| // | |
| mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress); | |
| } | |
| // | |
| // Allocate the private device structure for each disk | |
| // | |
| for (Index = DiskStart; Index < DiskEnd; Index++) { | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (BIOS_BLOCK_IO_DEV), | |
| (VOID **) &BiosBlockIoPrivate | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Error; | |
| } | |
| // | |
| // Zero the private device structure | |
| // | |
| ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV)); | |
| // | |
| // Initialize the private device structure | |
| // | |
| BiosBlockIoPrivate->Signature = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE; | |
| BiosBlockIoPrivate->ControllerHandle = Controller; | |
| BiosBlockIoPrivate->LegacyBios = LegacyBios; | |
| BiosBlockIoPrivate->PciIo = PciIo; | |
| BiosBlockIoPrivate->Bios.Floppy = FALSE; | |
| BiosBlockIoPrivate->Bios.Number = (UINT8) Index; | |
| BiosBlockIoPrivate->Bios.Letter = (UINT8) (Index - 0x80 + 'C'); | |
| BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE; | |
| if (BiosInitBlockIo (BiosBlockIoPrivate)) { | |
| SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath); | |
| // | |
| // Install the Block Io Protocol onto a new child handle | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &BiosBlockIoPrivate->Handle, | |
| &gEfiBlockIoProtocolGuid, | |
| &BiosBlockIoPrivate->BlockIo, | |
| &gEfiDevicePathProtocolGuid, | |
| BiosBlockIoPrivate->DevicePath, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->FreePool (BiosBlockIoPrivate); | |
| } | |
| // | |
| // Open For Child Device | |
| // | |
| Status = gBS->OpenProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &BiosBlockIoPrivate->PciIo, | |
| This->DriverBindingHandle, | |
| BiosBlockIoPrivate->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| } else { | |
| gBS->FreePool (BiosBlockIoPrivate); | |
| } | |
| } | |
| Error: | |
| if (EFI_ERROR (Status)) { | |
| if (PciIo != NULL) { | |
| if (DeviceEnable) { | |
| PciIo->Attributes ( | |
| PciIo, | |
| EfiPciIoAttributeOperationDisable, | |
| EFI_PCI_DEVICE_ENABLE, | |
| NULL | |
| ); | |
| } | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| if (PciDevPath != NULL) { | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| } | |
| if (mBufferUnder1Mb != 0 && mActiveInstances == 0) { | |
| gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE); | |
| // | |
| // Clear the buffer back to 0 | |
| // | |
| EfiAcquireLock (&mGlobalDataLock); | |
| mBufferUnder1Mb = 0; | |
| EfiReleaseLock (&mGlobalDataLock); | |
| } | |
| } | |
| } else { | |
| // | |
| // Successfully installed, so increment the number of active instances | |
| // | |
| EfiAcquireLock (&mGlobalDataLock); | |
| mActiveInstances++; | |
| EfiReleaseLock (&mGlobalDataLock); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Stop the device handled by this driver. | |
| @param This The driver binding protocol. | |
| @param Controller The controller to release. | |
| @param NumberOfChildren The number of handles in ChildHandleBuffer. | |
| @param ChildHandleBuffer The array of child handle. | |
| @retval EFI_SUCCESS The device was stopped. | |
| @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. | |
| @retval Others Fail to uninstall protocols attached on the device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BiosBlockIoDriverBindingStop ( | |
| IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
| IN EFI_HANDLE Controller, | |
| IN UINTN NumberOfChildren, | |
| IN EFI_HANDLE *ChildHandleBuffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BOOLEAN AllChildrenStopped; | |
| EFI_BLOCK_IO_PROTOCOL *BlockIo; | |
| BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate; | |
| UINTN Index; | |
| // | |
| // Decrement the number of active instances | |
| // | |
| if (mActiveInstances != 0) { | |
| // | |
| // Add a check since the stop function will be called 2 times for each handle | |
| // | |
| EfiAcquireLock (&mGlobalDataLock); | |
| mActiveInstances--; | |
| EfiReleaseLock (&mGlobalDataLock); | |
| } | |
| if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) { | |
| // | |
| // Free our global buffer | |
| // | |
| Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE); | |
| ASSERT_EFI_ERROR (Status); | |
| EfiAcquireLock (&mGlobalDataLock); | |
| mBufferUnder1Mb = 0; | |
| EfiReleaseLock (&mGlobalDataLock); | |
| } | |
| AllChildrenStopped = TRUE; | |
| for (Index = 0; Index < NumberOfChildren; Index++) { | |
| Status = gBS->OpenProtocol ( | |
| ChildHandleBuffer[Index], | |
| &gEfiBlockIoProtocolGuid, | |
| (VOID **) &BlockIo, | |
| This->DriverBindingHandle, | |
| Controller, | |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo); | |
| // | |
| // Release PCI I/O and Block IO Protocols on the clild handle. | |
| // | |
| Status = gBS->UninstallMultipleProtocolInterfaces ( | |
| ChildHandleBuffer[Index], | |
| &gEfiBlockIoProtocolGuid, | |
| &BiosBlockIoPrivate->BlockIo, | |
| &gEfiDevicePathProtocolGuid, | |
| BiosBlockIoPrivate->DevicePath, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| AllChildrenStopped = FALSE; | |
| } | |
| // | |
| // Shutdown the hardware | |
| // | |
| BiosBlockIoPrivate->PciIo->Attributes ( | |
| BiosBlockIoPrivate->PciIo, | |
| EfiPciIoAttributeOperationDisable, | |
| EFI_PCI_DEVICE_ENABLE, | |
| NULL | |
| ); | |
| gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| ChildHandleBuffer[Index] | |
| ); | |
| gBS->FreePool (BiosBlockIoPrivate); | |
| } | |
| if (!AllChildrenStopped) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| Status = gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiDevicePathProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| Status = gBS->CloseProtocol ( | |
| Controller, | |
| &gEfiPciIoProtocolGuid, | |
| This->DriverBindingHandle, | |
| Controller | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Build device path for device. | |
| @param BaseDevicePath Base device path. | |
| @param Drive Legacy drive. | |
| @param DevicePath Device path for output. | |
| **/ | |
| VOID | |
| SetBiosInitBlockIoDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath, | |
| IN BIOS_LEGACY_DRIVE *Drive, | |
| OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BLOCKIO_VENDOR_DEVICE_PATH VendorNode; | |
| Status = EFI_UNSUPPORTED; | |
| // | |
| // BugBug: Check for memory leaks! | |
| // | |
| if (Drive->EddVersion == EDD_VERSION_30) { | |
| // | |
| // EDD 3.0 case. | |
| // | |
| Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // EDD 1.1 device case or it is unrecognized EDD 3.0 device | |
| // | |
| ZeroMem (&VendorNode, sizeof (VendorNode)); | |
| VendorNode.DevicePath.Header.Type = HARDWARE_DEVICE_PATH; | |
| VendorNode.DevicePath.Header.SubType = HW_VENDOR_DP; | |
| SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode)); | |
| CopyMem (&VendorNode.DevicePath.Guid, &gBlockIoVendorGuid, sizeof (EFI_GUID)); | |
| VendorNode.LegacyDriveLetter = Drive->Number; | |
| *DevicePath = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header); | |
| } | |
| } | |
| /** | |
| Build device path for EDD 3.0. | |
| @param BaseDevicePath Base device path. | |
| @param Drive Legacy drive. | |
| @param DevicePath Device path for output. | |
| @retval EFI_SUCCESS The device path is built successfully. | |
| @retval EFI_UNSUPPORTED It is failed to built device path. | |
| **/ | |
| EFI_STATUS | |
| BuildEdd30DevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath, | |
| IN BIOS_LEGACY_DRIVE *Drive, | |
| IN EFI_DEVICE_PATH_PROTOCOL **DevicePath | |
| ) | |
| { | |
| // | |
| // AVL UINT64 Address; | |
| // AVL EFI_HANDLE Handle; | |
| // | |
| EFI_DEV_PATH Node; | |
| UINT32 Controller; | |
| Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller; | |
| ZeroMem (&Node, sizeof (Node)); | |
| if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) || | |
| (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0) | |
| ) { | |
| // | |
| // ATA or ATAPI drive found | |
| // | |
| Node.Atapi.Header.Type = MESSAGING_DEVICE_PATH; | |
| Node.Atapi.Header.SubType = MSG_ATAPI_DP; | |
| SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH)); | |
| Node.Atapi.SlaveMaster = Drive->Parameters.DevicePath.Atapi.Master; | |
| Node.Atapi.Lun = Drive->Parameters.DevicePath.Atapi.Lun; | |
| Node.Atapi.PrimarySecondary = (UINT8) Controller; | |
| } else { | |
| // | |
| // Not an ATA/ATAPI drive | |
| // | |
| if (Controller != 0) { | |
| ZeroMem (&Node, sizeof (Node)); | |
| Node.Controller.Header.Type = HARDWARE_DEVICE_PATH; | |
| Node.Controller.Header.SubType = HW_CONTROLLER_DP; | |
| SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH)); | |
| Node.Controller.ControllerNumber = Controller; | |
| *DevicePath = AppendDevicePathNode (*DevicePath, &Node.DevPath); | |
| } | |
| ZeroMem (&Node, sizeof (Node)); | |
| if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) { | |
| // | |
| // SCSI drive | |
| // | |
| Node.Scsi.Header.Type = MESSAGING_DEVICE_PATH; | |
| Node.Scsi.Header.SubType = MSG_SCSI_DP; | |
| SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH)); | |
| // | |
| // Lun is miss aligned in both EDD and Device Path data structures. | |
| // thus we do a byte copy, to prevent alignment traps on IA-64. | |
| // | |
| CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16)); | |
| Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun; | |
| } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) { | |
| // | |
| // USB drive | |
| // | |
| Node.Usb.Header.Type = MESSAGING_DEVICE_PATH; | |
| Node.Usb.Header.SubType = MSG_USB_DP; | |
| SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH)); | |
| Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved; | |
| } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) { | |
| // | |
| // 1394 drive | |
| // | |
| Node.F1394.Header.Type = MESSAGING_DEVICE_PATH; | |
| Node.F1394.Header.SubType = MSG_1394_DP; | |
| SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH)); | |
| Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid; | |
| } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) { | |
| // | |
| // Fibre drive | |
| // | |
| Node.FibreChannel.Header.Type = MESSAGING_DEVICE_PATH; | |
| Node.FibreChannel.Header.SubType = MSG_FIBRECHANNEL_DP; | |
| SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH)); | |
| Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn; | |
| Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun; | |
| } else { | |
| DEBUG ( | |
| ( | |
| DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n", | |
| Drive->Number, | |
| Drive->Parameters.InterfaceType | |
| ) | |
| ); | |
| } | |
| } | |
| if (Node.DevPath.Type == 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath); | |
| return EFI_SUCCESS; | |
| } |