--- /dev/null
+/** @file\r
+ Copyright (c) 2006, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "idebus.h"\r
+\r
+BOOLEAN ChannelDeviceDetected = FALSE;\r
+BOOLEAN SlaveDeviceExist = FALSE;\r
+UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
+BOOLEAN MasterDeviceExist = FALSE;\r
+UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+UINT8\r
+IDEReadPortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port\r
+ )\r
+{\r
+ UINT8 Data;\r
+\r
+ Data = 0;\r
+ //\r
+ // perform 1-byte data read from register\r
+ //\r
+ PciIo->Io.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+ return Data;\r
+}\r
+\r
+/**\r
+ Reads multiple words of data from the IDE data port.\r
+ Call the IO abstraction once to do the complete read,\r
+ not one word at a time\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO instance\r
+ @param Port IO port to read\r
+ @param Count No. of UINT16's to read\r
+ @param Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEReadPortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ UINT16 *AlignedBuffer;\r
+ UINT16 *WorkingBuffer;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+ // not perform actual I/O operations if buffer pointer passed in is not at\r
+ // natural boundary. The "Buffer" argument is passed in by user and may not\r
+ // at 16-bit natural boundary.\r
+ //\r
+ Size = sizeof (UINT16) * Count;\r
+\r
+ gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ Size + 1,\r
+ (VOID**)&WorkingBuffer\r
+ );\r
+\r
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+ //\r
+ // Perform UINT16 data read from FIFO\r
+ //\r
+ PciIo->Io.Read (\r
+ PciIo,\r
+ EfiPciIoWidthFifoUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ Count,\r
+ (UINT16*)AlignedBuffer\r
+ );\r
+\r
+ //\r
+ // Copy data to user buffer\r
+ //\r
+ CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
+ gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortB (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ //\r
+ // perform 1-byte data write to register\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param PciIo TODO: add argument description\r
+ @param Port TODO: add argument description\r
+ @param Data TODO: add argument description\r
+\r
+ TODO: add return values\r
+\r
+**/\r
+VOID\r
+IDEWritePortW (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINT16 Data\r
+ )\r
+{\r
+ //\r
+ // perform 1-word data write to register\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ 1,\r
+ &Data\r
+ );\r
+}\r
+\r
+/**\r
+ Write multiple words of data to the IDE data port.\r
+ Call the IO abstraction once to do the complete read,\r
+ not one word at a time\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO instance\r
+ @param Port IO port to read\r
+ @param Count No. of UINT16's to read\r
+ @param Buffer Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+IDEWritePortWMultiple (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT16 Port,\r
+ IN UINTN Count,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ UINT16 *AlignedBuffer;\r
+ UINT32 *WorkingBuffer;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
+ // not perform actual I/O operations if buffer pointer passed in is not at\r
+ // natural boundary. The "Buffer" argument is passed in by user and may not\r
+ // at 16-bit natural boundary.\r
+ //\r
+ Size = sizeof (UINT16) * Count;\r
+\r
+ gBS->AllocatePool (\r
+ EfiBootServicesData,\r
+ Size + 1,\r
+ (VOID **) &WorkingBuffer\r
+ );\r
+\r
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
+\r
+ //\r
+ // Copy data from user buffer to working buffer\r
+ //\r
+ CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
+\r
+ //\r
+ // perform UINT16 data write to the FIFO\r
+ //\r
+ PciIo->Io.Write (\r
+ PciIo,\r
+ EfiPciIoWidthFifoUint16,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ (UINT64) Port,\r
+ Count,\r
+ (UINT16 *) AlignedBuffer\r
+ );\r
+\r
+ gBS->FreePool (WorkingBuffer);\r
+}\r
+\r
+//\r
+// GetIdeRegistersBaseAddr\r
+//\r
+/**\r
+ Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
+ use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
+ the PCI IDE controller's Configuration Space.\r
+\r
+ The steps to get IDE IO port registers' base addresses for each channel\r
+ as follows:\r
+\r
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
+ controller's Configuration Space to determine the operating mode.\r
+\r
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
+ <pre>\r
+ ___________________________________________\r
+ | | Command Block | Control Block |\r
+ | Channel | Registers | Registers |\r
+ |___________|_______________|_______________|\r
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
+ |___________|_______________|_______________|\r
+ | Secondary | 170h - 177h | 376h - 377h |\r
+ |___________|_______________|_______________|\r
+\r
+ Table 1. Compatibility resource mappings\r
+ </pre>\r
+\r
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
+ <pre>\r
+ ___________________________________________________\r
+ | | Command Block | Control Block |\r
+ | Channel | Registers | Registers |\r
+ |___________|___________________|___________________|\r
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
+ |___________|___________________|___________________|\r
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
+ |___________|___________________|___________________|\r
+\r
+ Table 2. BARs for Register Mapping\r
+ </pre>\r
+ @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
+ primary, 0374h for secondary. So 2 bytes extra offset should be\r
+ added to the base addresses read from BARs.\r
+\r
+ For more details, please refer to PCI IDE Controller Specification and Intel\r
+ ICH4 Datasheet.\r
+\r
+ @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+ @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
+ receive IDE IO port registers' base addresses\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
+ )\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_UNSUPPORTED - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ PCI_TYPE00 PciData;\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ sizeof (PciData),\r
+ &PciData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
+ (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
+ } else {\r
+ //\r
+ // The BARs should be of IO type\r
+ //\r
+ if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
+ (PciData.Device.Bar[1] & BIT0) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
+ (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ }\r
+\r
+ if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ } else {\r
+ //\r
+ // The BARs should be of IO type\r
+ //\r
+ if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
+ (PciData.Device.Bar[3] & BIT0) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
+ (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to requery IDE resources. The IDE controller will\r
+ probably switch between native and legacy modes during the EFI->CSM->OS\r
+ transfer. We do this everytime before an BlkIo operation to ensure its\r
+ succeess.\r
+\r
+ @param IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+ReassignIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
+ UINT16 CommandBlockBaseAddr;\r
+ UINT16 ControlBlockBaseAddr;\r
+\r
+ //\r
+ // Requery IDE IO port registers' base addresses in case of the switch of\r
+ // native and legacy modes\r
+ //\r
+ Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
+\r
+ IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
+ (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+ IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+ IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+ IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+ IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+ IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+\r
+ (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+ (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
+ IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
+ IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
+\r
+ IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DiscoverIdeDevice\r
+//\r
+/**\r
+ Detect if there is disk connected to this port\r
+\r
+ @param IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverIdeDevice (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_NOT_FOUND - add return value to function comment\r
+// TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // If a channel has not been checked, check it now. Then set it to "checked" state\r
+ // After this step, all devices in this channel have been checked.\r
+ //\r
+ if (ChannelDeviceDetected == FALSE) {\r
+ Status = DetectIDEController (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ //\r
+ // Device exists. test if it is an ATA device.\r
+ // Prefer the result from DetectIDEController,\r
+ // if failed, try another device type to handle\r
+ // devices that not follow the spec.\r
+ //\r
+ if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
+ if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+ } else {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ MasterDeviceType = ATA_DEVICE_TYPE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
+ if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+ } else {\r
+ Status = ATAPIIdentify (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ATAIdentify (IdeDev);\r
+ if (!EFI_ERROR (Status)) {\r
+ SlaveDeviceType = ATA_DEVICE_TYPE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Init Block I/O interface\r
+ //\r
+ IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+ IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
+ IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
+ IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
+ IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
+\r
+ IdeDev->BlkMedia.LogicalPartition = FALSE;\r
+ IdeDev->BlkMedia.WriteCaching = FALSE;\r
+\r
+ //\r
+ // Init Disk Info interface\r
+ //\r
+ gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
+ IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
+ IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
+ IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
+ IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This interface is used to initialize all state data related to the detection of one\r
+ channel.\r
+\r
+ @retval EFI_SUCCESS Completed Successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+ VOID\r
+ )\r
+{\r
+ ChannelDeviceDetected = FALSE;\r
+ MasterDeviceExist = FALSE;\r
+ MasterDeviceType = 0xff;\r
+ SlaveDeviceExist = FALSE;\r
+ SlaveDeviceType = 0xff;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called by DiscoverIdeDevice(). It is used for detect\r
+ whether the IDE device exists in the specified Channel as the specified\r
+ Device Number.\r
+\r
+ There is two IDE channels: one is Primary Channel, the other is\r
+ Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
+ Different channel has different register group.\r
+\r
+ On each IDE channel, at most two IDE devices attach,\r
+ one is called Device 0 (Master device), the other is called Device 1\r
+ (Slave device). The devices on the same channel co-use the same register\r
+ group, so before sending out a command for a specified device via command\r
+ register, it is a must to select the current device to accept the command\r
+ by set the device number in the Head/Device Register.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @retval TRUE\r
+ successfully detects device.\r
+\r
+ @retval FALSE\r
+ any failure during detection process will return this\r
+ value.\r
+\r
+ @note\r
+ TODO: EFI_SUCCESS - add return value to function comment\r
+ TODO: EFI_NOT_FOUND - add return value to function comment\r
+\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 SectorCountReg;\r
+ UINT8 LBALowReg;\r
+ UINT8 LBAMidReg;\r
+ UINT8 LBAHighReg;\r
+ UINT8 InitStatusReg;\r
+ UINT8 StatusReg;\r
+\r
+ //\r
+ // Select slave device\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((1 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+\r
+ //\r
+ // Save the init slave status register\r
+ //\r
+ InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // Select Master back\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((0 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+\r
+ //\r
+ // Send ATA Device Execut Diagnostic command.\r
+ // This command should work no matter DRDY is ready or not\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
+\r
+ Status = WaitForBSYClear (IdeDev, 3500);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+ return Status;\r
+ }\r
+ //\r
+ // Read device signature\r
+ //\r
+ //\r
+ // Select Master\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((0 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+ SectorCountReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorCount\r
+ );\r
+ LBALowReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorNumber\r
+ );\r
+ LBAMidReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb\r
+ );\r
+ LBAHighReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb\r
+ );\r
+ if ((SectorCountReg == 0x1) &&\r
+ (LBALowReg == 0x1) &&\r
+ (LBAMidReg == 0x0) &&\r
+ (LBAHighReg == 0x0)) {\r
+ MasterDeviceExist = TRUE;\r
+ MasterDeviceType = ATA_DEVICE_TYPE;\r
+ } else {\r
+ if ((LBAMidReg == 0x14) &&\r
+ (LBAHighReg == 0xeb)) {\r
+ MasterDeviceExist = TRUE;\r
+ MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // For some Hard Drive, it takes some time to get\r
+ // the right signature when operating in single slave mode.\r
+ // We stall 20ms to work around this.\r
+ //\r
+ if (!MasterDeviceExist) {\r
+ gBS->Stall (20000);\r
+ }\r
+\r
+ //\r
+ // Select Slave\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((1 << 4) | 0xe0)\r
+ );\r
+ gBS->Stall (100);\r
+ SectorCountReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorCount\r
+ );\r
+ LBALowReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->SectorNumber\r
+ );\r
+ LBAMidReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderLsb\r
+ );\r
+ LBAHighReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->CylinderMsb\r
+ );\r
+ StatusReg = IDEReadPortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Reg.Status\r
+ );\r
+ if ((SectorCountReg == 0x1) &&\r
+ (LBALowReg == 0x1) &&\r
+ (LBAMidReg == 0x0) &&\r
+ (LBAHighReg == 0x0)) {\r
+ SlaveDeviceExist = TRUE;\r
+ SlaveDeviceType = ATA_DEVICE_TYPE;\r
+ } else {\r
+ if ((LBAMidReg == 0x14) &&\r
+ (LBAHighReg == 0xeb)) {\r
+ SlaveDeviceExist = TRUE;\r
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // When single master is plugged, slave device\r
+ // will be wrongly detected. Here's the workaround\r
+ // for ATA devices by detecting DRY bit in status\r
+ // register.\r
+ // NOTE: This workaround doesn't apply to ATAPI.\r
+ //\r
+ if (MasterDeviceExist && SlaveDeviceExist &&\r
+ (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
+ (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
+ MasterDeviceType == SlaveDeviceType &&\r
+ SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
+ SlaveDeviceExist = FALSE;\r
+ }\r
+\r
+ //\r
+ // Indicate this channel has been detected\r
+ //\r
+ ChannelDeviceDetected = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit clear in the Status\r
+ Register. DRQ is cleared when the device is finished transferring data.\r
+ So this function is called after data transfer is finished.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ clear.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not clear within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // wait for BSY == 0 and DRQ == 0\r
+ //\r
+ if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit clear in the Alternate\r
+ Status Register. DRQ is cleared when the device is finished\r
+ transferring data. So this function is called after data transfer\r
+ is finished.\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ clear.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not clear within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+\r
+ //\r
+ // wait for BSY == 0 and DRQ == 0\r
+ //\r
+ if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit set in the\r
+ Status Register.\r
+ DRQ is set when the device is ready to transfer data. So this function\r
+ is called after the command is sent to the device and before required\r
+ data is transferred.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not set within the time out.\r
+\r
+ @retval EFI_ABORTED\r
+ DRQ bit not set caused by the command abort.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ //\r
+ // read Status Register will clear interrupt\r
+ //\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+\r
+ //\r
+ // BSY==0,DRQ==1\r
+ //\r
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the DRQ bit set in the\r
+ Alternate Status Register. DRQ is set when the device is ready to\r
+ transfer data. So this function is called after the command\r
+ is sent to the device and before required data is transferred.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRQ bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRQ bit not set within the time out.\r
+\r
+ @retval EFI_ABORTED\r
+ DRQ bit not set caused by the command abort.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+\r
+ do {\r
+ //\r
+ // Read Alternate Status Register will not clear interrupt status\r
+ //\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ //\r
+ // BSY == 0 , DRQ == 1\r
+ //\r
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is used to poll for the BSY bit clear in the\r
+ Status Register. BSY is clear when the device is not busy.\r
+ Every command must be sent after device is not busy.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ BSY bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ BSY bit not clear within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Stall for 30 us\r
+ //\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+//\r
+// WaitForBSYClear2\r
+//\r
+/**\r
+ This function is used to poll for the BSY bit clear in the\r
+ Alternate Status Register. BSY is clear when the device is not busy.\r
+ Every command must be sent after device is not busy.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ BSY bit clear within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ BSY bit not clear within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN TimeoutInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+\r
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady\r
+//\r
+/**\r
+ This function is used to poll for the DRDY bit set in the\r
+ Status Register. DRDY bit is set when the device is ready\r
+ to accept command. Most ATA commands must be sent after\r
+ DRDY set except the ATAPI Packet Command.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRDY bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRDY bit not set within the time out.\r
+\r
+ @note\r
+ Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: DelayInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 StatusRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ //\r
+ // BSY == 0 , DRDY == 1\r
+ //\r
+ if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
+ break;\r
+ }\r
+\r
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// DRDYReady2\r
+//\r
+/**\r
+ This function is used to poll for the DRDY bit set in the\r
+ Alternate Status Register. DRDY bit is set when the device is ready\r
+ to accept command. Most ATA commands must be sent after\r
+ DRDY set except the ATAPI Packet Command.\r
+\r
+ @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] UINTN IN TimeoutInMilliSeconds\r
+ used to designate the timeout for the DRQ ready.\r
+\r
+ @retval EFI_SUCCESS\r
+ DRDY bit set within the time out.\r
+\r
+ @retval EFI_TIMEOUT\r
+ DRDY bit not set within the time out.\r
+\r
+ @note\r
+ Read Alternate Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINTN DelayInMilliSeconds\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+// TODO: function comment is missing 'Arguments:'\r
+// TODO: IdeDev - add argument and description to function comment\r
+// TODO: DelayInMilliSeconds - add argument and description to function comment\r
+// TODO: EFI_ABORTED - add return value to function comment\r
+{\r
+ UINT32 Delay;\r
+ UINT8 AltRegister;\r
+ UINT8 ErrorRegister;\r
+\r
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
+ do {\r
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+ //\r
+ // BSY == 0 , DRDY == 1\r
+ //\r
+ if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
+ break;\r
+ }\r
+\r
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+\r
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+ return EFI_ABORTED;\r
+ }\r
+ }\r
+\r
+ gBS->Stall (30);\r
+\r
+ Delay--;\r
+ } while (Delay);\r
+\r
+ if (Delay == 0) {\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SwapStringChars\r
+//\r
+/**\r
+ This function is a helper function used to change the char order in a\r
+ string. It is designed specially for the PrintAtaModuleName() function.\r
+ After the IDE device is detected, the IDE driver gets the device module\r
+ name by sending ATA command called ATA Identify Command or ATAPI\r
+ Identify Command to the specified IDE device. The module name returned\r
+ is a string of ASCII characters: the first character is bit8--bit15\r
+ of the first word, the second character is BIT0--bit7 of the first word\r
+ and so on. Thus the string can not be print directly before it is\r
+ preprocessed by this func to change the order of characters in\r
+ each word in the string.\r
+\r
+ @param[in] CHAR8 IN *Destination\r
+ Indicates the destination string.\r
+\r
+ @param[in] CHAR8 IN *Source\r
+ Indicates the source string.\r
+\r
+ @param[in] UINT8 IN Size\r
+ the length of the string\r
+\r
+**/\r
+VOID\r
+SwapStringChars (\r
+ IN CHAR8 *Destination,\r
+ IN CHAR8 *Source,\r
+ IN UINT32 Size\r
+ )\r
+{\r
+ UINT32 Index;\r
+ CHAR8 Temp;\r
+\r
+ for (Index = 0; Index < Size; Index += 2) {\r
+\r
+ Temp = Source[Index + 1];\r
+ Destination[Index + 1] = Source[Index];\r
+ Destination[Index] = Temp;\r
+ }\r
+}\r
+\r
+//\r
+// ReleaseIdeResources\r
+//\r
+/**\r
+ Release resources of an IDE device before stopping it.\r
+\r
+ @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
+\r
+**/\r
+VOID\r
+ReleaseIdeResources (\r
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
+ )\r
+{\r
+ if (IdeBlkIoDevice == NULL) {\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
+ //\r
+\r
+ if (IdeBlkIoDevice->SenseData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->SenseData);\r
+ IdeBlkIoDevice->SenseData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->Cache != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->Cache);\r
+ IdeBlkIoDevice->Cache = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->pIdData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->pIdData);\r
+ IdeBlkIoDevice->pIdData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->pInquiryData != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
+ IdeBlkIoDevice->pInquiryData = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
+ IdeBlkIoDevice->ControllerNameTable = NULL;\r
+ }\r
+\r
+ if (IdeBlkIoDevice->IoPort != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->IoPort);\r
+ }\r
+\r
+ if (IdeBlkIoDevice->DevicePath != NULL) {\r
+ gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
+ }\r
+\r
+ if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
+ gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
+ IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
+ }\r
+\r
+ gBS->FreePool (IdeBlkIoDevice);\r
+ IdeBlkIoDevice = NULL;\r
+\r
+ return ;\r
+}\r
+\r
+//\r
+// SetDeviceTransferMode\r
+//\r
+/**\r
+ Set the calculated Best transfer mode to a detected device\r
+\r
+ @param[in] *IdeDev Standard IDE device private data structure\r
+ @param[in] *TransferMode The device transfer mode to be set\r
+\r
+ @return Set transfer mode Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDeviceTransferMode (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATA_TRANSFER_MODE *TransferMode\r
+ )\r
+// TODO: function comment is missing 'Routine Description:'\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceSelect;\r
+ UINT8 SectorCount;\r
+\r
+ DeviceSelect = 0;\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+ SectorCount = *((UINT8 *) TransferMode);\r
+\r
+ //\r
+ // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_CMD_SET_FEATURES,\r
+ DeviceSelect,\r
+ 0x03,\r
+ SectorCount,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send ATA command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaLow The value in LBA_LOW register\r
+ @param LbaMiddle The value in LBA_MIDDLE register\r
+ @param LbaHigh The value in LBA_HIGH register\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT8 Feature,\r
+ IN UINT8 SectorCount,\r
+ IN UINT8 LbaLow,\r
+ IN UINT8 LbaMiddle,\r
+ IN UINT8 LbaHigh\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Wait for command completion\r
+ // For ATAPI_SMART_CMD, we may need more timeout to let device\r
+ // adjust internal states.\r
+ //\r
+ if (AtaCommand == ATA_CMD_SMART) {\r
+ Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+ } else {\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+ //\r
+ // Failed to execute command, abort operation\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send ATA Ext command into device with NON_DATA protocol\r
+\r
+ @param IdeDev Standard IDE device private data structure\r
+ @param AtaCommand The ATA command to be sent\r
+ @param Device The value in Device register\r
+ @param Feature The value in Feature register\r
+ @param SectorCount The value in SectorCount register\r
+ @param LbaAddress The LBA address in 48-bit mode\r
+\r
+ @retval EFI_SUCCESS Reading succeed\r
+ @retval EFI_ABORTED Command failed\r
+ @retval EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN UINT8 AtaCommand,\r
+ IN UINT8 Device,\r
+ IN UINT16 Feature,\r
+ IN UINT16 SectorCount,\r
+ IN EFI_LBA LbaAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 StatusRegister;\r
+ UINT8 SectorCount8;\r
+ UINT8 Feature8;\r
+ UINT8 LbaLow;\r
+ UINT8 LbaMid;\r
+ UINT8 LbaHigh;\r
+\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+ //\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+ );\r
+\r
+ //\r
+ // ATA commands for ATA device must be issued when DRDY is set\r
+ //\r
+ Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Pass parameter into device register block\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+\r
+ //\r
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ Feature8 = (UINT8) (Feature >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ Feature8 = (UINT8) Feature;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
+ //\r
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+ //\r
+ SectorCount8 = (UINT8) (SectorCount >> 8);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ SectorCount8 = (UINT8) SectorCount;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
+ //\r
+ // Fill the start LBA registers, which are also two-byte FIFO\r
+ //\r
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ LbaLow = (UINT8) LbaAddress;\r
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+\r
+ //\r
+ // Send command via Command Register\r
+ //\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+ //\r
+ // Wait for command completion\r
+ //\r
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+ //\r
+ // Failed to execute command, abort operation\r
+ //\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// SetDriveParameters\r
+//\r
+/**\r
+ Set drive parameters for devices not support PACKETS command\r
+\r
+ @param[in] IdeDev Standard IDE device private data structure\r
+ @param[in] DriveParameters The device parameters to be set into the disk\r
+\r
+ @return SetParameters Command execute status\r
+\r
+**/\r
+EFI_STATUS\r
+SetDriveParameters (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN ATA_DRIVE_PARMS *DriveParameters\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 DeviceSelect;\r
+\r
+ DeviceSelect = 0;\r
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
+\r
+ //\r
+ // Send Init drive parameters\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_CMD_INIT_DRIVE_PARAM,\r
+ (UINT8) (DeviceSelect + DriveParameters->Heads),\r
+ 0,\r
+ DriveParameters->Sector,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // Send Set Multiple parameters\r
+ //\r
+ Status = AtaNonDataCommandIn (\r
+ IdeDev,\r
+ ATA_CMD_SET_MULTIPLE_MODE,\r
+ DeviceSelect,\r
+ 0,\r
+ DriveParameters->MultipleSector,\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ TODO: Add function description\r
+\r
+ @param IdeDev TODO: add argument description\r
+\r
+ @retval EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
+EFI_STATUS\r
+EnableInterrupt (\r
+ IN IDE_BLK_IO_DEV *IdeDev\r
+ )\r
+{\r
+ UINT8 DeviceControl;\r
+\r
+ //\r
+ // Enable interrupt for DMA operation\r
+ //\r
+ DeviceControl = 0;\r
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
+\r
+ @param[in] Event Pointer to this event\r
+ @param[in] Context Event hanlder private data\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearInterrupt (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 IoPortForBmis;\r
+ UINT8 RegisterValue;\r
+ IDE_BLK_IO_DEV *IdeDev;\r
+\r
+ //\r
+ // Get our context\r
+ //\r
+ IdeDev = (IDE_BLK_IO_DEV *) Context;\r
+\r
+ //\r
+ // Obtain IDE IO port registers' base addresses\r
+ //\r
+ Status = ReassignIdeResources (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Check whether interrupt is pending\r
+ //\r
+\r
+ //\r
+ // Reset IDE device to force it de-assert interrupt pin\r
+ // Note: this will reset all devices on this IDE channel\r
+ //\r
+ AtaSoftReset (IdeDev);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Get base address of IDE Bus Master Status Regsiter\r
+ //\r
+ if (IdePrimary == IdeDev->Channel) {\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+ } else {\r
+ if (IdeSecondary == IdeDev->Channel) {\r
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+ } else {\r
+ return;\r
+ }\r
+ }\r
+ //\r
+ // Read BMIS register and clear ERROR and INTR bit\r
+ //\r
+ IdeDev->PciIo->Io.Read (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+ IdeDev->PciIo->Io.Write (\r
+ IdeDev->PciIo,\r
+ EfiPciIoWidthUint8,\r
+ EFI_PCI_IO_PASS_THROUGH_BAR,\r
+ IoPortForBmis,\r
+ 1,\r
+ &RegisterValue\r
+ );\r
+\r
+ //\r
+ // Select the other device on this channel to ensure this device to release the interrupt pin\r
+ //\r
+ if (IdeDev->Device == 0) {\r
+ RegisterValue = (1 << 4) | 0xe0;\r
+ } else {\r
+ RegisterValue = (0 << 4) | 0xe0;\r
+ }\r
+ IDEWritePortB (\r
+ IdeDev->PciIo,\r
+ IdeDev->IoPort->Head,\r
+ RegisterValue\r
+ );\r
+\r
+}\r
+++ /dev/null
-/** @file\r
- Copyright (c) 2006, Intel Corporation\r
- All rights reserved. This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "idebus.h"\r
-\r
-BOOLEAN ChannelDeviceDetected = FALSE;\r
-BOOLEAN SlaveDeviceExist = FALSE;\r
-UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
-BOOLEAN MasterDeviceExist = FALSE;\r
-UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
-\r
-/**\r
- TODO: Add function description\r
-\r
- @param PciIo TODO: add argument description\r
- @param Port TODO: add argument description\r
-\r
- TODO: add return values\r
-\r
-**/\r
-UINT8\r
-IDEReadPortB (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port\r
- )\r
-{\r
- UINT8 Data;\r
-\r
- Data = 0;\r
- //\r
- // perform 1-byte data read from register\r
- //\r
- PciIo->Io.Read (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
- return Data;\r
-}\r
-\r
-/**\r
- Reads multiple words of data from the IDE data port.\r
- Call the IO abstraction once to do the complete read,\r
- not one word at a time\r
-\r
- @param PciIo Pointer to the EFI_PCI_IO instance\r
- @param Port IO port to read\r
- @param Count No. of UINT16's to read\r
- @param Buffer Pointer to the data buffer for read\r
-\r
-**/\r
-VOID\r
-IDEReadPortWMultiple (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINTN Count,\r
- IN VOID *Buffer\r
- )\r
-{\r
- UINT16 *AlignedBuffer;\r
- UINT16 *WorkingBuffer;\r
- UINTN Size;\r
-\r
- //\r
- // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
- // not perform actual I/O operations if buffer pointer passed in is not at\r
- // natural boundary. The "Buffer" argument is passed in by user and may not\r
- // at 16-bit natural boundary.\r
- //\r
- Size = sizeof (UINT16) * Count;\r
-\r
- gBS->AllocatePool (\r
- EfiBootServicesData,\r
- Size + 1,\r
- (VOID**)&WorkingBuffer\r
- );\r
-\r
- AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
-\r
- //\r
- // Perform UINT16 data read from FIFO\r
- //\r
- PciIo->Io.Read (\r
- PciIo,\r
- EfiPciIoWidthFifoUint16,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- Count,\r
- (UINT16*)AlignedBuffer\r
- );\r
-\r
- //\r
- // Copy data to user buffer\r
- //\r
- CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
- gBS->FreePool (WorkingBuffer);\r
-}\r
-\r
-/**\r
- TODO: Add function description\r
-\r
- @param PciIo TODO: add argument description\r
- @param Port TODO: add argument description\r
- @param Data TODO: add argument description\r
-\r
- TODO: add return values\r
-\r
-**/\r
-VOID\r
-IDEWritePortB (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINT8 Data\r
- )\r
-{\r
- //\r
- // perform 1-byte data write to register\r
- //\r
- PciIo->Io.Write (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
-\r
-}\r
-\r
-/**\r
- TODO: Add function description\r
-\r
- @param PciIo TODO: add argument description\r
- @param Port TODO: add argument description\r
- @param Data TODO: add argument description\r
-\r
- TODO: add return values\r
-\r
-**/\r
-VOID\r
-IDEWritePortW (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINT16 Data\r
- )\r
-{\r
- //\r
- // perform 1-word data write to register\r
- //\r
- PciIo->Io.Write (\r
- PciIo,\r
- EfiPciIoWidthUint16,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- 1,\r
- &Data\r
- );\r
-}\r
-\r
-/**\r
- Write multiple words of data to the IDE data port.\r
- Call the IO abstraction once to do the complete read,\r
- not one word at a time\r
-\r
- @param PciIo Pointer to the EFI_PCI_IO instance\r
- @param Port IO port to read\r
- @param Count No. of UINT16's to read\r
- @param Buffer Pointer to the data buffer for read\r
-\r
-**/\r
-VOID\r
-IDEWritePortWMultiple (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT16 Port,\r
- IN UINTN Count,\r
- IN VOID *Buffer\r
- )\r
-{\r
- UINT16 *AlignedBuffer;\r
- UINT32 *WorkingBuffer;\r
- UINTN Size;\r
-\r
- //\r
- // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
- // not perform actual I/O operations if buffer pointer passed in is not at\r
- // natural boundary. The "Buffer" argument is passed in by user and may not\r
- // at 16-bit natural boundary.\r
- //\r
- Size = sizeof (UINT16) * Count;\r
-\r
- gBS->AllocatePool (\r
- EfiBootServicesData,\r
- Size + 1,\r
- (VOID **) &WorkingBuffer\r
- );\r
-\r
- AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
-\r
- //\r
- // Copy data from user buffer to working buffer\r
- //\r
- CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
-\r
- //\r
- // perform UINT16 data write to the FIFO\r
- //\r
- PciIo->Io.Write (\r
- PciIo,\r
- EfiPciIoWidthFifoUint16,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- (UINT64) Port,\r
- Count,\r
- (UINT16 *) AlignedBuffer\r
- );\r
-\r
- gBS->FreePool (WorkingBuffer);\r
-}\r
-\r
-//\r
-// GetIdeRegistersBaseAddr\r
-//\r
-/**\r
- Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
- use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
- the PCI IDE controller's Configuration Space.\r
-\r
- The steps to get IDE IO port registers' base addresses for each channel\r
- as follows:\r
-\r
- 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
- controller's Configuration Space to determine the operating mode.\r
-\r
- 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
- <pre>\r
- ___________________________________________\r
- | | Command Block | Control Block |\r
- | Channel | Registers | Registers |\r
- |___________|_______________|_______________|\r
- | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
- |___________|_______________|_______________|\r
- | Secondary | 170h - 177h | 376h - 377h |\r
- |___________|_______________|_______________|\r
-\r
- Table 1. Compatibility resource mappings\r
- </pre>\r
-\r
- b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
- in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
- <pre>\r
- ___________________________________________________\r
- | | Command Block | Control Block |\r
- | Channel | Registers | Registers |\r
- |___________|___________________|___________________|\r
- | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
- |___________|___________________|___________________|\r
- | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
- |___________|___________________|___________________|\r
-\r
- Table 2. BARs for Register Mapping\r
- </pre>\r
- @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
- primary, 0374h for secondary. So 2 bytes extra offset should be\r
- added to the base addresses read from BARs.\r
-\r
- For more details, please refer to PCI IDE Controller Specification and Intel\r
- ICH4 Datasheet.\r
-\r
- @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
- @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
- receive IDE IO port registers' base addresses\r
-\r
-**/\r
-EFI_STATUS\r
-GetIdeRegistersBaseAddr (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
- )\r
-// TODO: EFI_UNSUPPORTED - add return value to function comment\r
-// TODO: EFI_UNSUPPORTED - add return value to function comment\r
-// TODO: EFI_SUCCESS - add return value to function comment\r
-{\r
- EFI_STATUS Status;\r
- PCI_TYPE00 PciData;\r
-\r
- Status = PciIo->Pci.Read (\r
- PciIo,\r
- EfiPciIoWidthUint8,\r
- 0,\r
- sizeof (PciData),\r
- &PciData\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
- IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
- IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
- IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
- (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
- } else {\r
- //\r
- // The BARs should be of IO type\r
- //\r
- if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
- (PciData.Device.Bar[1] & BIT0) == 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
- (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
- IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
- IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
- }\r
-\r
- if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
- IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
- IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
- IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
- } else {\r
- //\r
- // The BARs should be of IO type\r
- //\r
- if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
- (PciData.Device.Bar[3] & BIT0) == 0) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
- (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
- IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
- IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
- (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to requery IDE resources. The IDE controller will\r
- probably switch between native and legacy modes during the EFI->CSM->OS\r
- transfer. We do this everytime before an BlkIo operation to ensure its\r
- succeess.\r
-\r
- @param IdeDev The BLK_IO private data which specifies the IDE device\r
-\r
-**/\r
-EFI_STATUS\r
-ReassignIdeResources (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
- )\r
-// TODO: EFI_SUCCESS - add return value to function comment\r
-{\r
- EFI_STATUS Status;\r
- IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
- UINT16 CommandBlockBaseAddr;\r
- UINT16 ControlBlockBaseAddr;\r
-\r
- //\r
- // Requery IDE IO port registers' base addresses in case of the switch of\r
- // native and legacy modes\r
- //\r
- Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
- CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
- ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
-\r
- IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
- (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
- IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
- IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
- IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
- IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
- IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
-\r
- (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
- (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
- IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
- IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
-\r
- IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// DiscoverIdeDevice\r
-//\r
-/**\r
- Detect if there is disk connected to this port\r
-\r
- @param IdeDev The BLK_IO private data which specifies the IDE device\r
-\r
-**/\r
-EFI_STATUS\r
-DiscoverIdeDevice (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
- )\r
-// TODO: EFI_NOT_FOUND - add return value to function comment\r
-// TODO: EFI_NOT_FOUND - add return value to function comment\r
-// TODO: EFI_SUCCESS - add return value to function comment\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // If a channel has not been checked, check it now. Then set it to "checked" state\r
- // After this step, all devices in this channel have been checked.\r
- //\r
- if (ChannelDeviceDetected == FALSE) {\r
- Status = DetectIDEController (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- }\r
-\r
- Status = EFI_NOT_FOUND;\r
-\r
- //\r
- // Device exists. test if it is an ATA device.\r
- // Prefer the result from DetectIDEController,\r
- // if failed, try another device type to handle\r
- // devices that not follow the spec.\r
- //\r
- if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
- if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
- Status = ATAIdentify (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- Status = ATAPIIdentify (IdeDev);\r
- if (!EFI_ERROR (Status)) {\r
- MasterDeviceType = ATAPI_DEVICE_TYPE;\r
- }\r
- }\r
- } else {\r
- Status = ATAPIIdentify (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- Status = ATAIdentify (IdeDev);\r
- if (!EFI_ERROR (Status)) {\r
- MasterDeviceType = ATA_DEVICE_TYPE;\r
- }\r
- }\r
- }\r
- }\r
- if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
- if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
- Status = ATAIdentify (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- Status = ATAPIIdentify (IdeDev);\r
- if (!EFI_ERROR (Status)) {\r
- SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
- }\r
- }\r
- } else {\r
- Status = ATAPIIdentify (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- Status = ATAIdentify (IdeDev);\r
- if (!EFI_ERROR (Status)) {\r
- SlaveDeviceType = ATA_DEVICE_TYPE;\r
- }\r
- }\r
- }\r
- }\r
- if (EFI_ERROR (Status)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- //\r
- // Init Block I/O interface\r
- //\r
- IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
- IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
- IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
- IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
- IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
-\r
- IdeDev->BlkMedia.LogicalPartition = FALSE;\r
- IdeDev->BlkMedia.WriteCaching = FALSE;\r
-\r
- //\r
- // Init Disk Info interface\r
- //\r
- gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
- IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
- IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
- IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
- IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This interface is used to initialize all state data related to the detection of one\r
- channel.\r
-\r
- @retval EFI_SUCCESS Completed Successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-InitializeIDEChannelData (\r
- VOID\r
- )\r
-{\r
- ChannelDeviceDetected = FALSE;\r
- MasterDeviceExist = FALSE;\r
- MasterDeviceType = 0xff;\r
- SlaveDeviceExist = FALSE;\r
- SlaveDeviceType = 0xff;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is called by DiscoverIdeDevice(). It is used for detect\r
- whether the IDE device exists in the specified Channel as the specified\r
- Device Number.\r
-\r
- There is two IDE channels: one is Primary Channel, the other is\r
- Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
- Different channel has different register group.\r
-\r
- On each IDE channel, at most two IDE devices attach,\r
- one is called Device 0 (Master device), the other is called Device 1\r
- (Slave device). The devices on the same channel co-use the same register\r
- group, so before sending out a command for a specified device via command\r
- register, it is a must to select the current device to accept the command\r
- by set the device number in the Head/Device Register.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @retval TRUE\r
- successfully detects device.\r
-\r
- @retval FALSE\r
- any failure during detection process will return this\r
- value.\r
-\r
- @note\r
- TODO: EFI_SUCCESS - add return value to function comment\r
- TODO: EFI_NOT_FOUND - add return value to function comment\r
-\r
-**/\r
-EFI_STATUS\r
-DetectIDEController (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 SectorCountReg;\r
- UINT8 LBALowReg;\r
- UINT8 LBAMidReg;\r
- UINT8 LBAHighReg;\r
- UINT8 InitStatusReg;\r
- UINT8 StatusReg;\r
-\r
- //\r
- // Select slave device\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((1 << 4) | 0xe0)\r
- );\r
- gBS->Stall (100);\r
-\r
- //\r
- // Save the init slave status register\r
- //\r
- InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
-\r
- //\r
- // Select Master back\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((0 << 4) | 0xe0)\r
- );\r
- gBS->Stall (100);\r
-\r
- //\r
- // Send ATA Device Execut Diagnostic command.\r
- // This command should work no matter DRDY is ready or not\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
-\r
- Status = WaitForBSYClear (IdeDev, 3500);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
- return Status;\r
- }\r
- //\r
- // Read device signature\r
- //\r
- //\r
- // Select Master\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((0 << 4) | 0xe0)\r
- );\r
- gBS->Stall (100);\r
- SectorCountReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->SectorCount\r
- );\r
- LBALowReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->SectorNumber\r
- );\r
- LBAMidReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->CylinderLsb\r
- );\r
- LBAHighReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->CylinderMsb\r
- );\r
- if ((SectorCountReg == 0x1) &&\r
- (LBALowReg == 0x1) &&\r
- (LBAMidReg == 0x0) &&\r
- (LBAHighReg == 0x0)) {\r
- MasterDeviceExist = TRUE;\r
- MasterDeviceType = ATA_DEVICE_TYPE;\r
- } else {\r
- if ((LBAMidReg == 0x14) &&\r
- (LBAHighReg == 0xeb)) {\r
- MasterDeviceExist = TRUE;\r
- MasterDeviceType = ATAPI_DEVICE_TYPE;\r
- }\r
- }\r
-\r
- //\r
- // For some Hard Drive, it takes some time to get\r
- // the right signature when operating in single slave mode.\r
- // We stall 20ms to work around this.\r
- //\r
- if (!MasterDeviceExist) {\r
- gBS->Stall (20000);\r
- }\r
-\r
- //\r
- // Select Slave\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((1 << 4) | 0xe0)\r
- );\r
- gBS->Stall (100);\r
- SectorCountReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->SectorCount\r
- );\r
- LBALowReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->SectorNumber\r
- );\r
- LBAMidReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->CylinderLsb\r
- );\r
- LBAHighReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->CylinderMsb\r
- );\r
- StatusReg = IDEReadPortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Reg.Status\r
- );\r
- if ((SectorCountReg == 0x1) &&\r
- (LBALowReg == 0x1) &&\r
- (LBAMidReg == 0x0) &&\r
- (LBAHighReg == 0x0)) {\r
- SlaveDeviceExist = TRUE;\r
- SlaveDeviceType = ATA_DEVICE_TYPE;\r
- } else {\r
- if ((LBAMidReg == 0x14) &&\r
- (LBAHighReg == 0xeb)) {\r
- SlaveDeviceExist = TRUE;\r
- SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
- }\r
- }\r
-\r
- //\r
- // When single master is plugged, slave device\r
- // will be wrongly detected. Here's the workaround\r
- // for ATA devices by detecting DRY bit in status\r
- // register.\r
- // NOTE: This workaround doesn't apply to ATAPI.\r
- //\r
- if (MasterDeviceExist && SlaveDeviceExist &&\r
- (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
- (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
- MasterDeviceType == SlaveDeviceType &&\r
- SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
- SlaveDeviceExist = FALSE;\r
- }\r
-\r
- //\r
- // Indicate this channel has been detected\r
- //\r
- ChannelDeviceDetected = TRUE;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to poll for the DRQ bit clear in the Status\r
- Register. DRQ is cleared when the device is finished transferring data.\r
- So this function is called after data transfer is finished.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ clear.\r
-\r
- @retval EFI_SUCCESS\r
- DRQ bit clear within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRQ bit not clear within the time out.\r
-\r
- @note\r
- Read Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRQClear (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-// TODO: EFI_ABORTED - add return value to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
-\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
-\r
- //\r
- // wait for BSY == 0 and DRQ == 0\r
- //\r
- if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
- break;\r
- }\r
-\r
- if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
-\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to poll for the DRQ bit clear in the Alternate\r
- Status Register. DRQ is cleared when the device is finished\r
- transferring data. So this function is called after data transfer\r
- is finished.\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ clear.\r
-\r
- @retval EFI_SUCCESS\r
- DRQ bit clear within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRQ bit not clear within the time out.\r
-\r
- @note\r
- Read Alternate Status Register will not clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRQClear2 (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-// TODO: EFI_ABORTED - add return value to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 AltRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
-\r
- AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
-\r
- //\r
- // wait for BSY == 0 and DRQ == 0\r
- //\r
- if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
- break;\r
- }\r
-\r
- if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
-\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to poll for the DRQ bit set in the\r
- Status Register.\r
- DRQ is set when the device is ready to transfer data. So this function\r
- is called after the command is sent to the device and before required\r
- data is transferred.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure,used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- DRQ bit set within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRQ bit not set within the time out.\r
-\r
- @retval EFI_ABORTED\r
- DRQ bit not set caused by the command abort.\r
-\r
- @note\r
- Read Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRQReady (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
- //\r
- // read Status Register will clear interrupt\r
- //\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
-\r
- //\r
- // BSY==0,DRQ==1\r
- //\r
- if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
- break;\r
- }\r
-\r
- if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to poll for the DRQ bit set in the\r
- Alternate Status Register. DRQ is set when the device is ready to\r
- transfer data. So this function is called after the command\r
- is sent to the device and before required data is transferred.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- DRQ bit set within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRQ bit not set within the time out.\r
-\r
- @retval EFI_ABORTED\r
- DRQ bit not set caused by the command abort.\r
-\r
- @note\r
- Read Alternate Status Register will not clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRQReady2 (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 AltRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
-\r
- do {\r
- //\r
- // Read Alternate Status Register will not clear interrupt status\r
- //\r
- AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
- //\r
- // BSY == 0 , DRQ == 1\r
- //\r
- if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
- break;\r
- }\r
-\r
- if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is used to poll for the BSY bit clear in the\r
- Status Register. BSY is clear when the device is not busy.\r
- Every command must be sent after device is not busy.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- BSY bit clear within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- BSY bit not clear within the time out.\r
-\r
- @note\r
- Read Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-WaitForBSYClear (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 StatusRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
-\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
- if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
- break;\r
- }\r
-\r
- //\r
- // Stall for 30 us\r
- //\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
-\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-//\r
-// WaitForBSYClear2\r
-//\r
-/**\r
- This function is used to poll for the BSY bit clear in the\r
- Alternate Status Register. BSY is clear when the device is not busy.\r
- Every command must be sent after device is not busy.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- BSY bit clear within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- BSY bit not clear within the time out.\r
-\r
- @note\r
- Read Alternate Status Register will not clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-WaitForBSYClear2 (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN TimeoutInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 AltRegister;\r
-\r
- Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
- AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
- if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
- break;\r
- }\r
-\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
-\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// DRDYReady\r
-//\r
-/**\r
- This function is used to poll for the DRDY bit set in the\r
- Status Register. DRDY bit is set when the device is ready\r
- to accept command. Most ATA commands must be sent after\r
- DRDY set except the ATAPI Packet Command.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- DRDY bit set within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRDY bit not set within the time out.\r
-\r
- @note\r
- Read Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRDYReady (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN DelayInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: DelayInMilliSeconds - add argument and description to function comment\r
-// TODO: EFI_ABORTED - add return value to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 StatusRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
- //\r
- // BSY == 0 , DRDY == 1\r
- //\r
- if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
- break;\r
- }\r
-\r
- if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// DRDYReady2\r
-//\r
-/**\r
- This function is used to poll for the DRDY bit set in the\r
- Alternate Status Register. DRDY bit is set when the device is ready\r
- to accept command. Most ATA commands must be sent after\r
- DRDY set except the ATAPI Packet Command.\r
-\r
- @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] UINTN IN TimeoutInMilliSeconds\r
- used to designate the timeout for the DRQ ready.\r
-\r
- @retval EFI_SUCCESS\r
- DRDY bit set within the time out.\r
-\r
- @retval EFI_TIMEOUT\r
- DRDY bit not set within the time out.\r
-\r
- @note\r
- Read Alternate Status Register will clear interrupt status.\r
-\r
-**/\r
-EFI_STATUS\r
-DRDYReady2 (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINTN DelayInMilliSeconds\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO: IdeDev - add argument and description to function comment\r
-// TODO: DelayInMilliSeconds - add argument and description to function comment\r
-// TODO: EFI_ABORTED - add return value to function comment\r
-{\r
- UINT32 Delay;\r
- UINT8 AltRegister;\r
- UINT8 ErrorRegister;\r
-\r
- Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
- do {\r
- AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
- //\r
- // BSY == 0 , DRDY == 1\r
- //\r
- if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
- break;\r
- }\r
-\r
- if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-\r
- ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
- if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
- return EFI_ABORTED;\r
- }\r
- }\r
-\r
- gBS->Stall (30);\r
-\r
- Delay--;\r
- } while (Delay);\r
-\r
- if (Delay == 0) {\r
- return EFI_TIMEOUT;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// SwapStringChars\r
-//\r
-/**\r
- This function is a helper function used to change the char order in a\r
- string. It is designed specially for the PrintAtaModuleName() function.\r
- After the IDE device is detected, the IDE driver gets the device module\r
- name by sending ATA command called ATA Identify Command or ATAPI\r
- Identify Command to the specified IDE device. The module name returned\r
- is a string of ASCII characters: the first character is bit8--bit15\r
- of the first word, the second character is BIT0--bit7 of the first word\r
- and so on. Thus the string can not be print directly before it is\r
- preprocessed by this func to change the order of characters in\r
- each word in the string.\r
-\r
- @param[in] CHAR8 IN *Destination\r
- Indicates the destination string.\r
-\r
- @param[in] CHAR8 IN *Source\r
- Indicates the source string.\r
-\r
- @param[in] UINT8 IN Size\r
- the length of the string\r
-\r
-**/\r
-VOID\r
-SwapStringChars (\r
- IN CHAR8 *Destination,\r
- IN CHAR8 *Source,\r
- IN UINT32 Size\r
- )\r
-{\r
- UINT32 Index;\r
- CHAR8 Temp;\r
-\r
- for (Index = 0; Index < Size; Index += 2) {\r
-\r
- Temp = Source[Index + 1];\r
- Destination[Index + 1] = Source[Index];\r
- Destination[Index] = Temp;\r
- }\r
-}\r
-\r
-//\r
-// ReleaseIdeResources\r
-//\r
-/**\r
- Release resources of an IDE device before stopping it.\r
-\r
- @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
-\r
-**/\r
-VOID\r
-ReleaseIdeResources (\r
- IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
- )\r
-{\r
- if (IdeBlkIoDevice == NULL) {\r
- return ;\r
- }\r
-\r
- //\r
- // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
- //\r
-\r
- if (IdeBlkIoDevice->SenseData != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->SenseData);\r
- IdeBlkIoDevice->SenseData = NULL;\r
- }\r
-\r
- if (IdeBlkIoDevice->Cache != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->Cache);\r
- IdeBlkIoDevice->Cache = NULL;\r
- }\r
-\r
- if (IdeBlkIoDevice->pIdData != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->pIdData);\r
- IdeBlkIoDevice->pIdData = NULL;\r
- }\r
-\r
- if (IdeBlkIoDevice->pInquiryData != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
- IdeBlkIoDevice->pInquiryData = NULL;\r
- }\r
-\r
- if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
- FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
- IdeBlkIoDevice->ControllerNameTable = NULL;\r
- }\r
-\r
- if (IdeBlkIoDevice->IoPort != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->IoPort);\r
- }\r
-\r
- if (IdeBlkIoDevice->DevicePath != NULL) {\r
- gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
- }\r
-\r
- if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
- gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
- IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
- }\r
-\r
- gBS->FreePool (IdeBlkIoDevice);\r
- IdeBlkIoDevice = NULL;\r
-\r
- return ;\r
-}\r
-\r
-//\r
-// SetDeviceTransferMode\r
-//\r
-/**\r
- Set the calculated Best transfer mode to a detected device\r
-\r
- @param[in] *IdeDev Standard IDE device private data structure\r
- @param[in] *TransferMode The device transfer mode to be set\r
-\r
- @return Set transfer mode Command execute status\r
-\r
-**/\r
-EFI_STATUS\r
-SetDeviceTransferMode (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN ATA_TRANSFER_MODE *TransferMode\r
- )\r
-// TODO: function comment is missing 'Routine Description:'\r
-{\r
- EFI_STATUS Status;\r
- UINT8 DeviceSelect;\r
- UINT8 SectorCount;\r
-\r
- DeviceSelect = 0;\r
- DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
- SectorCount = *((UINT8 *) TransferMode);\r
-\r
- //\r
- // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
- //\r
- Status = AtaNonDataCommandIn (\r
- IdeDev,\r
- ATA_CMD_SET_FEATURES,\r
- DeviceSelect,\r
- 0x03,\r
- SectorCount,\r
- 0,\r
- 0,\r
- 0\r
- );\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Send ATA command into device with NON_DATA protocol\r
-\r
- @param IdeDev Standard IDE device private data structure\r
- @param AtaCommand The ATA command to be sent\r
- @param Device The value in Device register\r
- @param Feature The value in Feature register\r
- @param SectorCount The value in SectorCount register\r
- @param LbaLow The value in LBA_LOW register\r
- @param LbaMiddle The value in LBA_MIDDLE register\r
- @param LbaHigh The value in LBA_HIGH register\r
-\r
- @retval EFI_SUCCESS Reading succeed\r
- @retval EFI_ABORTED Command failed\r
- @retval EFI_DEVICE_ERROR Device status error\r
-\r
-**/\r
-EFI_STATUS\r
-AtaNonDataCommandIn (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINT8 AtaCommand,\r
- IN UINT8 Device,\r
- IN UINT8 Feature,\r
- IN UINT8 SectorCount,\r
- IN UINT8 LbaLow,\r
- IN UINT8 LbaMiddle,\r
- IN UINT8 LbaHigh\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 StatusRegister;\r
-\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
- );\r
-\r
- //\r
- // ATA commands for ATA device must be issued when DRDY is set\r
- //\r
- Status = DRDYReady (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Pass parameter into device register block\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-\r
- //\r
- // Send command via Command Register\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
- //\r
- // Wait for command completion\r
- // For ATAPI_SMART_CMD, we may need more timeout to let device\r
- // adjust internal states.\r
- //\r
- if (AtaCommand == ATA_CMD_SMART) {\r
- Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
- } else {\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
- if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
- //\r
- // Failed to execute command, abort operation\r
- //\r
- return EFI_ABORTED;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Send ATA Ext command into device with NON_DATA protocol\r
-\r
- @param IdeDev Standard IDE device private data structure\r
- @param AtaCommand The ATA command to be sent\r
- @param Device The value in Device register\r
- @param Feature The value in Feature register\r
- @param SectorCount The value in SectorCount register\r
- @param LbaAddress The LBA address in 48-bit mode\r
-\r
- @retval EFI_SUCCESS Reading succeed\r
- @retval EFI_ABORTED Command failed\r
- @retval EFI_DEVICE_ERROR Device status error\r
-\r
-**/\r
-EFI_STATUS\r
-AtaNonDataCommandInExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN UINT8 AtaCommand,\r
- IN UINT8 Device,\r
- IN UINT16 Feature,\r
- IN UINT16 SectorCount,\r
- IN EFI_LBA LbaAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 StatusRegister;\r
- UINT8 SectorCount8;\r
- UINT8 Feature8;\r
- UINT8 LbaLow;\r
- UINT8 LbaMid;\r
- UINT8 LbaHigh;\r
-\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
- //\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
- );\r
-\r
- //\r
- // ATA commands for ATA device must be issued when DRDY is set\r
- //\r
- Status = DRDYReady (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Pass parameter into device register block\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
- //\r
- // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
- //\r
- Feature8 = (UINT8) (Feature >> 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
-\r
- Feature8 = (UINT8) Feature;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
-\r
- //\r
- // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
- //\r
- SectorCount8 = (UINT8) (SectorCount >> 8);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
- SectorCount8 = (UINT8) SectorCount;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
- //\r
- // Fill the start LBA registers, which are also two-byte FIFO\r
- //\r
- LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
- LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
- LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-\r
- LbaLow = (UINT8) LbaAddress;\r
- LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
- LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-\r
- //\r
- // Send command via Command Register\r
- //\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
- //\r
- // Wait for command completion\r
- //\r
- Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
- if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
- //\r
- // Failed to execute command, abort operation\r
- //\r
- return EFI_ABORTED;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-//\r
-// SetDriveParameters\r
-//\r
-/**\r
- Set drive parameters for devices not support PACKETS command\r
-\r
- @param[in] IdeDev Standard IDE device private data structure\r
- @param[in] DriveParameters The device parameters to be set into the disk\r
-\r
- @return SetParameters Command execute status\r
-\r
-**/\r
-EFI_STATUS\r
-SetDriveParameters (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN ATA_DRIVE_PARMS *DriveParameters\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 DeviceSelect;\r
-\r
- DeviceSelect = 0;\r
- DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
-\r
- //\r
- // Send Init drive parameters\r
- //\r
- Status = AtaNonDataCommandIn (\r
- IdeDev,\r
- ATA_CMD_INIT_DRIVE_PARAM,\r
- (UINT8) (DeviceSelect + DriveParameters->Heads),\r
- 0,\r
- DriveParameters->Sector,\r
- 0,\r
- 0,\r
- 0\r
- );\r
-\r
- //\r
- // Send Set Multiple parameters\r
- //\r
- Status = AtaNonDataCommandIn (\r
- IdeDev,\r
- ATA_CMD_SET_MULTIPLE_MODE,\r
- DeviceSelect,\r
- 0,\r
- DriveParameters->MultipleSector,\r
- 0,\r
- 0,\r
- 0\r
- );\r
- return Status;\r
-}\r
-\r
-/**\r
- TODO: Add function description\r
-\r
- @param IdeDev TODO: add argument description\r
-\r
- @retval EFI_SUCCESS TODO: Add description for return value\r
-\r
-**/\r
-EFI_STATUS\r
-EnableInterrupt (\r
- IN IDE_BLK_IO_DEV *IdeDev\r
- )\r
-{\r
- UINT8 DeviceControl;\r
-\r
- //\r
- // Enable interrupt for DMA operation\r
- //\r
- DeviceControl = 0;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
-\r
- @param[in] Event Pointer to this event\r
- @param[in] Context Event hanlder private data\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-ClearInterrupt (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT64 IoPortForBmis;\r
- UINT8 RegisterValue;\r
- IDE_BLK_IO_DEV *IdeDev;\r
-\r
- //\r
- // Get our context\r
- //\r
- IdeDev = (IDE_BLK_IO_DEV *) Context;\r
-\r
- //\r
- // Obtain IDE IO port registers' base addresses\r
- //\r
- Status = ReassignIdeResources (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
-\r
- //\r
- // Check whether interrupt is pending\r
- //\r
-\r
- //\r
- // Reset IDE device to force it de-assert interrupt pin\r
- // Note: this will reset all devices on this IDE channel\r
- //\r
- AtaSoftReset (IdeDev);\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
-\r
- //\r
- // Get base address of IDE Bus Master Status Regsiter\r
- //\r
- if (IdePrimary == IdeDev->Channel) {\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
- } else {\r
- if (IdeSecondary == IdeDev->Channel) {\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
- } else {\r
- return;\r
- }\r
- }\r
- //\r
- // Read BMIS register and clear ERROR and INTR bit\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Select the other device on this channel to ensure this device to release the interrupt pin\r
- //\r
- if (IdeDev->Device == 0) {\r
- RegisterValue = (1 << 4) | 0xe0;\r
- } else {\r
- RegisterValue = (0 << 4) | 0xe0;\r
- }\r
- IDEWritePortB (\r
- IdeDev->PciIo,\r
- IdeDev->IoPort->Head,\r
- RegisterValue\r
- );\r
-\r
-}\r