mirror of https://github.com/acidanthera/audk.git
301 lines
10 KiB
C
301 lines
10 KiB
C
|
/** @file
|
||
|
Collect IDE information from Native EFI Driver
|
||
|
|
||
|
Copyright (c) 2006 - 2010, 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 "LegacyBiosInterface.h"
|
||
|
|
||
|
BOOLEAN mIdeDataBuiltFlag = FALSE;
|
||
|
|
||
|
/**
|
||
|
Collect IDE Inquiry data from the IDE disks
|
||
|
|
||
|
@param Private Legacy BIOS Instance data
|
||
|
@param HddInfo Hdd Information
|
||
|
@param Flag Reconnect IdeController or not
|
||
|
|
||
|
@retval EFI_SUCCESS It should always work.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
LegacyBiosBuildIdeData (
|
||
|
IN LEGACY_BIOS_INSTANCE *Private,
|
||
|
IN HDD_INFO **HddInfo,
|
||
|
IN UINT16 Flag
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_HANDLE IdeController;
|
||
|
UINTN HandleCount;
|
||
|
EFI_HANDLE *HandleBuffer;
|
||
|
UINTN Index;
|
||
|
EFI_DISK_INFO_PROTOCOL *DiskInfo;
|
||
|
UINT32 IdeChannel;
|
||
|
UINT32 IdeDevice;
|
||
|
UINT32 Size;
|
||
|
UINT8 *InquiryData;
|
||
|
UINT32 InquiryDataSize;
|
||
|
HDD_INFO *LocalHddInfo;
|
||
|
UINT32 PciIndex;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
|
||
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
|
||
|
PCI_DEVICE_PATH *PciDevicePath;
|
||
|
|
||
|
//
|
||
|
// Only build data once
|
||
|
// We have a problem with GetBbsInfo in that it can be invoked two
|
||
|
// places. Once in BDS, when all EFI drivers are connected and once in
|
||
|
// LegacyBoot after all EFI drivers are disconnected causing this routine
|
||
|
// to hang. In LegacyBoot this function is also called before EFI drivers
|
||
|
// are disconnected.
|
||
|
// Cases covered
|
||
|
// GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
|
||
|
// GetBbsInfo not invoked in BDS. First invocation of this function
|
||
|
// proceeds normally and second via GetBbsInfo ignored.
|
||
|
//
|
||
|
PciDevicePath = NULL;
|
||
|
LocalHddInfo = *HddInfo;
|
||
|
Status = Private->LegacyBiosPlatform->GetPlatformHandle (
|
||
|
Private->LegacyBiosPlatform,
|
||
|
EfiGetPlatformIdeHandle,
|
||
|
0,
|
||
|
&HandleBuffer,
|
||
|
&HandleCount,
|
||
|
(VOID *) &LocalHddInfo
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
IdeController = HandleBuffer[0];
|
||
|
//
|
||
|
// Force IDE drive spin up!
|
||
|
//
|
||
|
if (Flag != 0) {
|
||
|
gBS->DisconnectController (
|
||
|
IdeController,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
}
|
||
|
|
||
|
gBS->ConnectController (IdeController, NULL, NULL, FALSE);
|
||
|
|
||
|
//
|
||
|
// Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
|
||
|
// And GetIdeHandle will switch to Legacy mode, if required.
|
||
|
//
|
||
|
Private->LegacyBiosPlatform->GetPlatformHandle (
|
||
|
Private->LegacyBiosPlatform,
|
||
|
EfiGetPlatformIdeHandle,
|
||
|
0,
|
||
|
&HandleBuffer,
|
||
|
&HandleCount,
|
||
|
(VOID *) &LocalHddInfo
|
||
|
);
|
||
|
}
|
||
|
|
||
|
mIdeDataBuiltFlag = TRUE;
|
||
|
|
||
|
//
|
||
|
// Get Identity command from all drives
|
||
|
//
|
||
|
gBS->LocateHandleBuffer (
|
||
|
ByProtocol,
|
||
|
&gEfiDiskInfoProtocolGuid,
|
||
|
NULL,
|
||
|
&HandleCount,
|
||
|
&HandleBuffer
|
||
|
);
|
||
|
|
||
|
Private->IdeDriveCount = (UINT8) HandleCount;
|
||
|
for (Index = 0; Index < HandleCount; Index++) {
|
||
|
Status = gBS->HandleProtocol (
|
||
|
HandleBuffer[Index],
|
||
|
&gEfiDiskInfoProtocolGuid,
|
||
|
(VOID **) &DiskInfo
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
|
||
|
//
|
||
|
// Locate which PCI device
|
||
|
//
|
||
|
Status = gBS->HandleProtocol (
|
||
|
HandleBuffer[Index],
|
||
|
&gEfiDevicePathProtocolGuid,
|
||
|
(VOID *) &DevicePath
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
DevicePathNode = DevicePath;
|
||
|
while (!IsDevicePathEnd (DevicePathNode)) {
|
||
|
TempDevicePathNode = NextDevicePathNode (DevicePathNode);
|
||
|
if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
|
||
|
( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
|
||
|
( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
|
||
|
( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
|
||
|
PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
|
||
|
break;
|
||
|
}
|
||
|
DevicePathNode = NextDevicePathNode (DevicePathNode);
|
||
|
}
|
||
|
|
||
|
if (PciDevicePath == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find start of PCI device in HddInfo. The assumption of the data
|
||
|
// structure is 2 controllers(channels) per PCI device and each
|
||
|
// controller can have 2 drives(devices).
|
||
|
// HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
|
||
|
// HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
|
||
|
// HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
|
||
|
// HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
|
||
|
// @bug eventually need to pass in max number of entries
|
||
|
// for end of for loop
|
||
|
//
|
||
|
for (PciIndex = 0; PciIndex < 8; PciIndex++) {
|
||
|
if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
|
||
|
(PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
|
||
|
) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PciIndex == 8) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Size = sizeof (ATAPI_IDENTIFY);
|
||
|
DiskInfo->Identify (
|
||
|
DiskInfo,
|
||
|
&LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
|
||
|
&Size
|
||
|
);
|
||
|
if (IdeChannel == 0) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
|
||
|
} else if (IdeChannel == 1) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
|
||
|
}
|
||
|
|
||
|
InquiryData = NULL;
|
||
|
InquiryDataSize = 0;
|
||
|
Status = DiskInfo->Inquiry (
|
||
|
DiskInfo,
|
||
|
NULL,
|
||
|
&InquiryDataSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
InquiryData = (UINT8 *) AllocatePool (
|
||
|
InquiryDataSize
|
||
|
);
|
||
|
if (InquiryData != NULL) {
|
||
|
Status = DiskInfo->Inquiry (
|
||
|
DiskInfo,
|
||
|
InquiryData,
|
||
|
&InquiryDataSize
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
Status = EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If ATAPI device then Inquiry will pass and ATA fail.
|
||
|
//
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
ASSERT (InquiryData != NULL);
|
||
|
//
|
||
|
// If IdeDevice = 0 then set master bit, else slave bit
|
||
|
//
|
||
|
if (IdeDevice == 0) {
|
||
|
if ((InquiryData[0] & 0x1f) == 0x05) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
|
||
|
} else if ((InquiryData[0] & 0x1f) == 0x00) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
|
||
|
}
|
||
|
} else {
|
||
|
if ((InquiryData[0] & 0x1f) == 0x05) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
|
||
|
} else if ((InquiryData[0] & 0x1f) == 0x00) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
|
||
|
}
|
||
|
}
|
||
|
FreePool (InquiryData);
|
||
|
} else {
|
||
|
if (IdeDevice == 0) {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
|
||
|
} else {
|
||
|
LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (HandleBuffer != NULL) {
|
||
|
FreePool (HandleBuffer);
|
||
|
}
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
If the IDE channel is in compatibility (legacy) mode, remove all
|
||
|
PCI I/O BAR addresses from the controller.
|
||
|
|
||
|
@param IdeController The handle of target IDE controller
|
||
|
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
InitLegacyIdeController (
|
||
|
IN EFI_HANDLE IdeController
|
||
|
)
|
||
|
{
|
||
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
||
|
UINT8 Pi;
|
||
|
UINT32 IOBarClear;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// If the IDE channel is in compatibility (legacy) mode, remove all
|
||
|
// PCI I/O BAR addresses from the controller. Some software gets
|
||
|
// confused if an IDE controller is in compatibility (legacy) mode
|
||
|
// and has PCI I/O resources allocated
|
||
|
//
|
||
|
Status = gBS->HandleProtocol (
|
||
|
IdeController,
|
||
|
&gEfiPciIoProtocolGuid,
|
||
|
(VOID **) &PciIo
|
||
|
);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
IOBarClear = 0x00;
|
||
|
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 1, &Pi);
|
||
|
if ((Pi & 0x01) == 0) {
|
||
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
|
||
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
|
||
|
}
|
||
|
if ((Pi & 0x04) == 0) {
|
||
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
|
||
|
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|