git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1319 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1770 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1770 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Copyright (c) 2006, Intel Corporation                                                         
 | |
|   All rights reserved. This program and the accompanying materials                          
 | |
|   are licensed and made available under the terms and conditions of the BSD License         
 | |
|   which accompanies this distribution.  The full text of the license may be found at        
 | |
|   http://opensource.org/licenses/bsd-license.php                                            
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "idebus.h"
 | |
| 
 | |
| BOOLEAN SlaveDeviceExist  = FALSE;
 | |
| BOOLEAN MasterDeviceExist = FALSE;
 | |
| 
 | |
| /**
 | |
|   TODO: Add function description
 | |
| 
 | |
|   @param  PciIo TODO: add argument description
 | |
|   @param  Port TODO: add argument description
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| **/
 | |
| UINT8
 | |
| IDEReadPortB (
 | |
|   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | |
|   IN  UINT16                Port
 | |
|   )
 | |
| {
 | |
|   UINT8 Data;
 | |
| 
 | |
|   Data = 0;
 | |
|   //
 | |
|   // perform 1-byte data read from register
 | |
|   //
 | |
|   PciIo->Io.Read (
 | |
|               PciIo,
 | |
|               EfiPciIoWidthUint8,
 | |
|               EFI_PCI_IO_PASS_THROUGH_BAR,
 | |
|               (UINT64) Port,
 | |
|               1,
 | |
|               &Data
 | |
|               );
 | |
|   return Data;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads multiple words of data from the IDE data port. 
 | |
|   Call the IO abstraction once to do the complete read,
 | |
|   not one word at a time
 | |
| 
 | |
|   @param  PciIo Pointer to the EFI_PCI_IO instance
 | |
|   @param  Port IO port to read
 | |
|   @param  Count No. of UINT16's to read
 | |
|   @param  Buffer Pointer to the data buffer for read
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IDEReadPortWMultiple (
 | |
|   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | |
|   IN  UINT16                Port,
 | |
|   IN  UINTN                 Count,
 | |
|   IN  VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   UINT16  *AlignedBuffer;
 | |
|   UINT16  *WorkingBuffer;
 | |
|   UINTN   Size;
 | |
| 
 | |
|   //
 | |
|   // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
 | |
|   // not perform actual I/O operations if buffer pointer passed in is not at
 | |
|   // natural boundary. The "Buffer" argument is passed in by user and may not
 | |
|   // at 16-bit natural boundary.
 | |
|   //
 | |
|   Size = sizeof (UINT16) * Count;
 | |
| 
 | |
|   gBS->AllocatePool (
 | |
|         EfiBootServicesData,
 | |
|         Size + 1,
 | |
|         (VOID**)&WorkingBuffer
 | |
|         );
 | |
| 
 | |
|   AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
 | |
| 
 | |
|   //
 | |
|   // Perform UINT16 data read from FIFO
 | |
|   //
 | |
|   PciIo->Io.Read (
 | |
|               PciIo,
 | |
|               EfiPciIoWidthFifoUint16,
 | |
|               EFI_PCI_IO_PASS_THROUGH_BAR,
 | |
|               (UINT64) Port,
 | |
|               Count,
 | |
|               (UINT16*)AlignedBuffer
 | |
|               );
 | |
| 
 | |
|   //
 | |
|   // Copy data to user buffer
 | |
|   //
 | |
|   CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);
 | |
|   gBS->FreePool (WorkingBuffer);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   TODO: Add function description
 | |
| 
 | |
|   @param  PciIo TODO: add argument description
 | |
|   @param  Port TODO: add argument description
 | |
|   @param  Data TODO: add argument description
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IDEWritePortB (
 | |
|   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | |
|   IN  UINT16                Port,
 | |
|   IN  UINT8                 Data
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // perform 1-byte data write to register
 | |
|   //
 | |
|   PciIo->Io.Write (
 | |
|               PciIo,
 | |
|               EfiPciIoWidthUint8,
 | |
|               EFI_PCI_IO_PASS_THROUGH_BAR,
 | |
|               (UINT64) Port,
 | |
|               1,
 | |
|               &Data
 | |
|               );
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   TODO: Add function description
 | |
| 
 | |
|   @param  PciIo TODO: add argument description
 | |
|   @param  Port TODO: add argument description
 | |
|   @param  Data TODO: add argument description
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IDEWritePortW (
 | |
|   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | |
|   IN  UINT16                Port,
 | |
|   IN  UINT16                Data
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // perform 1-word data write to register
 | |
|   //
 | |
|   PciIo->Io.Write (
 | |
|               PciIo,
 | |
|               EfiPciIoWidthUint16,
 | |
|               EFI_PCI_IO_PASS_THROUGH_BAR,
 | |
|               (UINT64) Port,
 | |
|               1,
 | |
|               &Data
 | |
|               );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write multiple words of data to the IDE data port. 
 | |
|   Call the IO abstraction once to do the complete read,
 | |
|   not one word at a time
 | |
| 
 | |
|   @param  PciIo Pointer to the EFI_PCI_IO instance
 | |
|   @param  Port IO port to read
 | |
|   @param  Count No. of UINT16's to read
 | |
|   @param  Buffer Pointer to the data buffer for read
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IDEWritePortWMultiple (
 | |
|   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | |
|   IN  UINT16                Port,
 | |
|   IN  UINTN                 Count,
 | |
|   IN  VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   UINT16  *AlignedBuffer;
 | |
|   UINT32  *WorkingBuffer;
 | |
|   UINTN   Size;
 | |
| 
 | |
|   //
 | |
|   // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
 | |
|   // not perform actual I/O operations if buffer pointer passed in is not at
 | |
|   // natural boundary. The "Buffer" argument is passed in by user and may not
 | |
|   // at 16-bit natural boundary.
 | |
|   //
 | |
|   Size = sizeof (UINT16) * Count;
 | |
| 
 | |
|   gBS->AllocatePool (
 | |
|         EfiBootServicesData,
 | |
|         Size + 1,
 | |
|         (VOID **) &WorkingBuffer
 | |
|         );
 | |
| 
 | |
|   AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
 | |
| 
 | |
|   //
 | |
|   // Copy data from user buffer to working buffer
 | |
|   //
 | |
|   CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);
 | |
| 
 | |
|   //
 | |
|   // perform UINT16 data write to the FIFO
 | |
|   //
 | |
|   PciIo->Io.Write (
 | |
|               PciIo,
 | |
|               EfiPciIoWidthFifoUint16,
 | |
|               EFI_PCI_IO_PASS_THROUGH_BAR,
 | |
|               (UINT64) Port,
 | |
|               Count,
 | |
|               (UINT16 *) AlignedBuffer
 | |
|               );
 | |
| 
 | |
|   gBS->FreePool (WorkingBuffer);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   TODO: Add function description
 | |
| 
 | |
|   @param  IdeDev TODO: add argument description
 | |
| 
 | |
|   TODO: add return values
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| BadIdeDeviceCheck (
 | |
|   IN IDE_BLK_IO_DEV *IdeDev
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   //  check whether all registers return 0xff,
 | |
|   //  if so, deem the channel is disabled.
 | |
|   //
 | |
| #ifdef EFI_DEBUG
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| 
 | |
| #else
 | |
| 
 | |
|   return FALSE;
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| //
 | |
| // GetIdeRegistersBaseAddr
 | |
| //
 | |
| /**
 | |
|   Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
 | |
|   use fixed addresses. In Native-PCI mode, get base addresses from BARs in
 | |
|   the PCI IDE controller's Configuration Space.
 | |
| 
 | |
|   The steps to get IDE IO port registers' base addresses for each channel 
 | |
|   as follows:
 | |
| 
 | |
|   1. Examine the Programming Interface byte of the Class Code fields in PCI IDE 
 | |
|   controller's Configuration Space to determine the operating mode.
 | |
| 
 | |
|   2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
 | |
|   <pre>
 | |
|   ___________________________________________
 | |
|   |           | Command Block | Control Block |
 | |
|   |  Channel  |   Registers   |   Registers   |
 | |
|   |___________|_______________|_______________|
 | |
|   |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
 | |
|   |___________|_______________|_______________|
 | |
|   | Secondary |  170h - 177h  |  376h - 377h  |
 | |
|   |___________|_______________|_______________|
 | |
| 
 | |
|   Table 1. Compatibility resource mappings
 | |
|   </pre>
 | |
| 
 | |
|   b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
 | |
|   in IDE controller's PCI Configuration Space, shown in the Table 2 below.
 | |
|   <pre>
 | |
|   ___________________________________________________
 | |
|   |           |   Command Block   |   Control Block   |
 | |
|   |  Channel  |     Registers     |     Registers     |
 | |
|   |___________|___________________|___________________|
 | |
|   |  Primary  | BAR at offset 0x10| BAR at offset 0x14|
 | |
|   |___________|___________________|___________________|
 | |
|   | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
 | |
|   |___________|___________________|___________________|
 | |
| 
 | |
|   Table 2. BARs for Register Mapping
 | |
|   </pre>
 | |
|   @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for 
 | |
|   primary, 0374h for secondary. So 2 bytes extra offset should be 
 | |
|   added to the base addresses read from BARs.
 | |
| 
 | |
|   For more details, please refer to PCI IDE Controller Specification and Intel 
 | |
|   ICH4 Datasheet.
 | |
| 
 | |
|   @param  PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
 | |
|   @param  IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
 | |
|   receive IDE IO port registers' base addresses
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetIdeRegistersBaseAddr (
 | |
|   IN  EFI_PCI_IO_PROTOCOL         *PciIo,
 | |
|   OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
 | |
|   )
 | |
| // TODO:    EFI_UNSUPPORTED - add return value to function comment
 | |
| // TODO:    EFI_UNSUPPORTED - add return value to function comment
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   PCI_TYPE00  PciData;
 | |
| 
 | |
|   Status = PciIo->Pci.Read (
 | |
|                         PciIo,
 | |
|                         EfiPciIoWidthUint8,
 | |
|                         0,
 | |
|                         sizeof (PciData),
 | |
|                         &PciData
 | |
|                         );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
 | |
|     IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;
 | |
|     IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;
 | |
|     IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     = 
 | |
|     (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));
 | |
|   } else {
 | |
|     //
 | |
|     // The BARs should be of IO type
 | |
|     //
 | |
|     if ((PciData.Device.Bar[0] & bit0) == 0 || 
 | |
|         (PciData.Device.Bar[1] & bit0) == 0) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  =
 | |
|     (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
 | |
|     IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  =
 | |
|     (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
 | |
|     IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =
 | |
|     (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
 | |
|   }
 | |
| 
 | |
|   if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
 | |
|     IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  = 0x170;
 | |
|     IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  = 0x376;
 | |
|     IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =
 | |
|     (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
 | |
|   } else {
 | |
|     //
 | |
|     // The BARs should be of IO type
 | |
|     //
 | |
|     if ((PciData.Device.Bar[2] & bit0) == 0 ||
 | |
|         (PciData.Device.Bar[3] & bit0) == 0) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr  =
 | |
|     (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
 | |
|     IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr  =
 | |
|     (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
 | |
|     IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr     =
 | |
|     (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to requery IDE resources. The IDE controller will 
 | |
|   probably switch between native and legacy modes during the EFI->CSM->OS 
 | |
|   transfer. We do this everytime before an BlkIo operation to ensure its
 | |
|   succeess.
 | |
| 
 | |
|   @param  IdeDev The BLK_IO private data which specifies the IDE device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ReassignIdeResources (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev
 | |
|   )
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
 | |
|   UINT16                  CommandBlockBaseAddr;
 | |
|   UINT16                  ControlBlockBaseAddr;
 | |
| 
 | |
|   //
 | |
|   // Requery IDE IO port registers' base addresses in case of the switch of
 | |
|   // native and legacy modes
 | |
|   //
 | |
|   Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));
 | |
|   CommandBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;
 | |
|   ControlBlockBaseAddr                = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;
 | |
| 
 | |
|   IdeDev->IoPort->Data                = CommandBlockBaseAddr;
 | |
|   (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
 | |
|   IdeDev->IoPort->SectorCount         = (UINT16) (CommandBlockBaseAddr + 0x02);
 | |
|   IdeDev->IoPort->SectorNumber        = (UINT16) (CommandBlockBaseAddr + 0x03);
 | |
|   IdeDev->IoPort->CylinderLsb         = (UINT16) (CommandBlockBaseAddr + 0x04);
 | |
|   IdeDev->IoPort->CylinderMsb         = (UINT16) (CommandBlockBaseAddr + 0x05);
 | |
|   IdeDev->IoPort->Head                = (UINT16) (CommandBlockBaseAddr + 0x06);
 | |
| 
 | |
|   (*(UINT16 *) &IdeDev->IoPort->Reg)  = (UINT16) (CommandBlockBaseAddr + 0x07);
 | |
|   (*(UINT16 *) &IdeDev->IoPort->Alt)  = ControlBlockBaseAddr;
 | |
|   IdeDev->IoPort->DriveAddress        = (UINT16) (ControlBlockBaseAddr + 0x01);
 | |
|   IdeDev->IoPort->MasterSlave         = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);
 | |
| 
 | |
|   IdeDev->IoPort->BusMasterBaseAddr   = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read SATA registers to detect SATA disks
 | |
| 
 | |
|   @param  IdeDev The BLK_IO private data which specifies the IDE device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CheckPowerMode (
 | |
|   IDE_BLK_IO_DEV    *IdeDev
 | |
|   )
 | |
| // TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| // TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| {
 | |
|   UINT8       ErrorRegister;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((IdeDev->Device << 4) | 0xe0)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists
 | |
|   // a device (initial state). Normally, BSY is also in clear state if there is
 | |
|   // no device
 | |
|   //
 | |
|   Status = WaitForBSYClear (IdeDev, 31000);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // select device, read error register
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((IdeDev->Device << 4) | 0xe0)
 | |
|     );
 | |
|   Status        = DRDYReady (IdeDev, 200);
 | |
| 
 | |
|   ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|   if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) {
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| }
 | |
| 
 | |
| //
 | |
| // DiscoverIdeDevice
 | |
| //
 | |
| /**
 | |
|   Detect if there is disk connected to this port
 | |
| 
 | |
|   @param  IdeDev The BLK_IO private data which specifies the IDE device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DiscoverIdeDevice (
 | |
|   IN IDE_BLK_IO_DEV *IdeDev
 | |
|   )
 | |
| // TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| // TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| // TODO:    EFI_SUCCESS - add return value to function comment
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   BOOLEAN     SataFlag;
 | |
| 
 | |
|   SataFlag = FALSE;
 | |
|   //
 | |
|   // This extra detection is for SATA disks
 | |
|   //
 | |
|   Status = CheckPowerMode (IdeDev);
 | |
|   if (Status == EFI_SUCCESS) {
 | |
|     SataFlag = TRUE;
 | |
|   }
 | |
|     
 | |
|   //
 | |
|   // If a channel has not been checked, check it now. Then set it to "checked" state
 | |
|   // After this step, all devices in this channel have been checked.
 | |
|   //
 | |
|   Status = DetectIDEController (IdeDev);
 | |
| 
 | |
|   if ((EFI_ERROR (Status)) && !SataFlag) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Device exists. test if it is an ATA device
 | |
|   //
 | |
|   Status = ATAIdentify (IdeDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // if not ATA device, test if it is an ATAPI device
 | |
|     //
 | |
|     Status = ATAPIIdentify (IdeDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // if not ATAPI device either, return error.
 | |
|       //
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Init Block I/O interface
 | |
|   //
 | |
|   IdeDev->BlkIo.Revision            = EFI_BLOCK_IO_PROTOCOL_REVISION;
 | |
|   IdeDev->BlkIo.Reset               = IDEBlkIoReset;
 | |
|   IdeDev->BlkIo.ReadBlocks          = IDEBlkIoReadBlocks;
 | |
|   IdeDev->BlkIo.WriteBlocks         = IDEBlkIoWriteBlocks;
 | |
|   IdeDev->BlkIo.FlushBlocks         = IDEBlkIoFlushBlocks;
 | |
| 
 | |
|   IdeDev->BlkMedia.LogicalPartition = FALSE;
 | |
|   IdeDev->BlkMedia.WriteCaching     = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Init Disk Info interface
 | |
|   //
 | |
|   gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));
 | |
|   IdeDev->DiskInfo.Inquiry    = IDEDiskInfoInquiry;
 | |
|   IdeDev->DiskInfo.Identify   = IDEDiskInfoIdentify;
 | |
|   IdeDev->DiskInfo.SenseData  = IDEDiskInfoSenseData;
 | |
|   IdeDev->DiskInfo.WhichIde   = IDEDiskInfoWhichIde;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is called by DiscoverIdeDevice(). It is used for detect 
 | |
|   whether the IDE device exists in the specified Channel as the specified 
 | |
|   Device Number.
 | |
| 
 | |
|   There is two IDE channels: one is Primary Channel, the other is 
 | |
|   Secondary Channel.(Channel is the logical name for the physical "Cable".) 
 | |
|   Different channel has different register group.
 | |
| 
 | |
|   On each IDE channel, at most two IDE devices attach, 
 | |
|   one is called Device 0 (Master device), the other is called Device 1 
 | |
|   (Slave device). The devices on the same channel co-use the same register 
 | |
|   group, so before sending out a command for a specified device via command 
 | |
|   register, it is a must to select the current device to accept the command 
 | |
|   by set the device number in the Head/Device Register.
 | |
| 
 | |
|   @param[in] *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
| 
 | |
|   @retval TRUE
 | |
|   successfully detects device.
 | |
|   
 | |
|   @retval FALSE
 | |
|   any failure during detection process will return this
 | |
|   value.
 | |
| 
 | |
|   @note
 | |
|   TODO:    EFI_SUCCESS - add return value to function comment
 | |
|   TODO:    EFI_NOT_FOUND - add return value to function comment
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DetectIDEController (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT8       ErrorReg;
 | |
|   UINT8       StatusReg;
 | |
|   UINT8       InitStatusReg;
 | |
|   EFI_STATUS  DeviceStatus;
 | |
| 
 | |
|   //
 | |
|   // Slave device has been detected with master device.
 | |
|   //
 | |
|   if ((IdeDev->Device) == 1) {
 | |
|     if (SlaveDeviceExist) {
 | |
|       //
 | |
|       // If master not exists but slave exists, slave have to wait a while
 | |
|       //
 | |
|       if (!MasterDeviceExist) {
 | |
|         //
 | |
|         // if single slave can't be detected, add delay 4s here.
 | |
|         //
 | |
|         gBS->Stall (4000000);
 | |
|       }
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     } else {
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|   }
 | |
|       
 | |
|   //
 | |
|   // Select slave device
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((1 << 4) | 0xe0)
 | |
|     );
 | |
|   gBS->Stall (100);
 | |
| 
 | |
|   //
 | |
|   // Save the init slave status register
 | |
|   //
 | |
|   InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
| 
 | |
|   //
 | |
|   // Select master back
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((0 << 4) | 0xe0)
 | |
|     );
 | |
|   gBS->Stall (100);
 | |
|   //
 | |
|   // Send ATA Device Execut Diagnostic command.
 | |
|   // This command should work no matter DRDY is ready or not
 | |
|   //
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
 | |
| 
 | |
|   Status    = WaitForBSYClear (IdeDev, 3500);
 | |
| 
 | |
|   ErrorReg  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
| 
 | |
|   //
 | |
|   // Master Error register is 0x01. D0 passed, D1 passed or not present.
 | |
|   // Master Error register is 0x81. D0 passed, D1 failed. Return.
 | |
|   // Master Error register is other value. D0 failed, D1 passed or not present..
 | |
|   //
 | |
|   if (ErrorReg == 0x01) {
 | |
|     MasterDeviceExist = TRUE;
 | |
|     DeviceStatus      = EFI_SUCCESS;
 | |
|   } else if (ErrorReg == 0x81) {
 | |
| 
 | |
|     MasterDeviceExist = TRUE;
 | |
|     DeviceStatus      = EFI_SUCCESS;
 | |
|     SlaveDeviceExist  = FALSE;
 | |
| 
 | |
|     return DeviceStatus;
 | |
|   } else {
 | |
|     MasterDeviceExist = FALSE;
 | |
|     DeviceStatus      = EFI_NOT_FOUND;
 | |
|   }
 | |
|     
 | |
|   //
 | |
|   // Master Error register is not 0x81, Go on check Slave
 | |
|   //
 | |
|   
 | |
|   //
 | |
|   // Stall 10ms to wait for slave device ready
 | |
|   //
 | |
|   gBS->Stall (10000);
 | |
|   
 | |
|   //
 | |
|   // select slave
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((1 << 4) | 0xe0)
 | |
|     );
 | |
| 
 | |
|   gBS->Stall (300);
 | |
|   ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
| 
 | |
|   //
 | |
|   // Slave Error register is not 0x01, D1 failed. Return.
 | |
|   //
 | |
|   if (ErrorReg != 0x01) {
 | |
|     SlaveDeviceExist = FALSE;
 | |
|     return DeviceStatus;
 | |
|   }
 | |
| 
 | |
|   StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
| 
 | |
|   //
 | |
|   // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate
 | |
|   //   "ATAPI TEST UNIT READY" command
 | |
|   //
 | |
|   if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) {
 | |
|     Status = AtapiTestUnitReady (IdeDev);
 | |
| 
 | |
|     //
 | |
|     // Still fail, Slave doesn't exist.
 | |
|     //
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       SlaveDeviceExist = FALSE;
 | |
|       return DeviceStatus;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Error reg is 0x01 and DRDY is ready,
 | |
|   //  or ATAPI test unit ready success,
 | |
|   //  or  init Slave status DRDY is ready
 | |
|   // Slave exists.
 | |
|   //
 | |
|   SlaveDeviceExist = TRUE;
 | |
| 
 | |
|   return DeviceStatus;
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to poll for the DRQ bit clear in the Status 
 | |
|   Register. DRQ is cleared when the device is finished transferring data. 
 | |
|   So this function is called after data transfer is finished.
 | |
| 
 | |
|   @param[in] *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ clear.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRQ bit clear within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRQ bit not clear within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Status Register will clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRQClear (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| // TODO:    EFI_ABORTED - add return value to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   StatusRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
| 
 | |
|     StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
| 
 | |
|     //
 | |
|     // wait for BSY == 0 and DRQ == 0
 | |
|     //
 | |
|     if ((StatusRegister & (DRQ | BSY)) == 0) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((StatusRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     //  Stall for 30 us
 | |
|     //
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
| 
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to poll for the DRQ bit clear in the Alternate 
 | |
|   Status Register. DRQ is cleared when the device is finished 
 | |
|   transferring data. So this function is called after data transfer
 | |
|   is finished.
 | |
| 
 | |
|   @param[in] *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ clear.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRQ bit clear within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRQ bit not clear within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Alternate Status Register will not clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRQClear2 (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| // TODO:    EFI_ABORTED - add return value to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   AltRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
| 
 | |
|     AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
 | |
| 
 | |
|     //
 | |
|     //  wait for BSY == 0 and DRQ == 0
 | |
|     //
 | |
|     if ((AltRegister & (DRQ | BSY)) == 0) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((AltRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Stall for 30 us
 | |
|     //
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
| 
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to poll for the DRQ bit set in the 
 | |
|   Status Register.
 | |
|   DRQ is set when the device is ready to transfer data. So this function
 | |
|   is called after the command is sent to the device and before required 
 | |
|   data is transferred.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure,used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRQ bit set within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRQ bit not set within the time out.
 | |
|   
 | |
|   @retval EFI_ABORTED
 | |
|   DRQ bit not set caused by the command abort.
 | |
| 
 | |
|   @note
 | |
|   Read Status Register will clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRQReady (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   StatusRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
|     //
 | |
|     //  read Status Register will clear interrupt
 | |
|     //
 | |
|     StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
| 
 | |
|     //
 | |
|     //  BSY==0,DRQ==1
 | |
|     //
 | |
|     if ((StatusRegister & (BSY | DRQ)) == DRQ) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((StatusRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Stall for 30 us
 | |
|     //
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to poll for the DRQ bit set in the 
 | |
|   Alternate Status Register. DRQ is set when the device is ready to 
 | |
|   transfer data. So this function is called after the command 
 | |
|   is sent to the device and before required data is transferred.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRQ bit set within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRQ bit not set within the time out.
 | |
|   
 | |
|   @retval EFI_ABORTED
 | |
|   DRQ bit not set caused by the command abort.
 | |
| 
 | |
|   @note
 | |
|   Read Alternate Status Register will not clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRQReady2 (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   AltRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     //  Read Alternate Status Register will not clear interrupt status
 | |
|     //
 | |
|     AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
 | |
|     //
 | |
|     // BSY == 0 , DRQ == 1
 | |
|     //
 | |
|     if ((AltRegister & (BSY | DRQ)) == DRQ) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((AltRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Stall for 30 us
 | |
|     //
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is used to poll for the BSY bit clear in the 
 | |
|   Status Register. BSY is clear when the device is not busy.
 | |
|   Every command must be sent after device is not busy.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   BSY bit clear within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   BSY bit not clear within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Status Register will clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| WaitForBSYClear (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   StatusRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
| 
 | |
|     StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
|     if ((StatusRegister & BSY) == 0x00) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Stall for 30 us
 | |
|     //
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
| 
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| //
 | |
| // WaitForBSYClear2
 | |
| //
 | |
| /**
 | |
|   This function is used to poll for the BSY bit clear in the 
 | |
|   Alternate Status Register. BSY is clear when the device is not busy.
 | |
|   Every command must be sent after device is not busy.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   BSY bit clear within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   BSY bit not clear within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Alternate Status Register will not clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| WaitForBSYClear2 (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           TimeoutInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    TimeoutInMilliSeconds - add argument and description to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   AltRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
|     AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
 | |
|     if ((AltRegister & BSY) == 0x00) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
| 
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // DRDYReady
 | |
| //
 | |
| /**
 | |
|   This function is used to poll for the DRDY bit set in the 
 | |
|   Status Register. DRDY bit is set when the device is ready 
 | |
|   to accept command. Most ATA commands must be sent after 
 | |
|   DRDY set except the ATAPI Packet Command.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRDY bit set within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRDY bit not set within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Status Register will clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRDYReady (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           DelayInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    DelayInMilliSeconds - add argument and description to function comment
 | |
| // TODO:    EFI_ABORTED - add return value to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   StatusRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
|     StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
|     //
 | |
|     //  BSY == 0 , DRDY == 1
 | |
|     //
 | |
|     if ((StatusRegister & (DRDY | BSY)) == DRDY) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((StatusRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     gBS->Stall (15);
 | |
| 
 | |
|     Delay--;
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // DRDYReady2
 | |
| //
 | |
| /**
 | |
|   This function is used to poll for the DRDY bit set in the 
 | |
|   Alternate Status Register. DRDY bit is set when the device is ready 
 | |
|   to accept command. Most ATA commands must be sent after 
 | |
|   DRDY set except the ATAPI Packet Command.
 | |
| 
 | |
|   @param[in] IDE_BLK_IO_DEV  IN    *IdeDev
 | |
|   pointer pointing to IDE_BLK_IO_DEV data structure, used
 | |
|   to record all the information of the IDE device.
 | |
|   
 | |
|   @param[in] UINTN     IN    TimeoutInMilliSeconds
 | |
|   used to designate the timeout for the DRQ ready.
 | |
| 
 | |
|   @retval EFI_SUCCESS
 | |
|   DRDY bit set within the time out.
 | |
|   
 | |
|   @retval EFI_TIMEOUT
 | |
|   DRDY bit not set within the time out.
 | |
| 
 | |
|   @note
 | |
|   Read Alternate Status Register will clear interrupt status.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DRDYReady2 (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINTN           DelayInMilliSeconds
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| // TODO: function comment is missing 'Arguments:'
 | |
| // TODO:    IdeDev - add argument and description to function comment
 | |
| // TODO:    DelayInMilliSeconds - add argument and description to function comment
 | |
| // TODO:    EFI_ABORTED - add return value to function comment
 | |
| {
 | |
|   UINT32  Delay;
 | |
|   UINT8   AltRegister;
 | |
|   UINT8   ErrorRegister;
 | |
| 
 | |
|   Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
 | |
|   do {
 | |
|     AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
 | |
|     //
 | |
|     //  BSY == 0 , DRDY == 1
 | |
|     //
 | |
|     if ((AltRegister & (DRDY | BSY)) == DRDY) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if ((AltRegister & (BSY | ERR)) == ERR) {
 | |
| 
 | |
|       ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
 | |
|       if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     gBS->Stall (30);
 | |
| 
 | |
|     Delay--;
 | |
|   } while (Delay);
 | |
| 
 | |
|   if (Delay == 0) {
 | |
|     return EFI_TIMEOUT;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // SwapStringChars
 | |
| //
 | |
| /**
 | |
|   This function is a helper function used to change the char order in a 
 | |
|   string. It is designed specially for the PrintAtaModuleName() function.
 | |
|   After the IDE device is detected, the IDE driver gets the device module
 | |
|   name by sending ATA command called ATA Identify Command or ATAPI 
 | |
|   Identify Command to the specified IDE device. The module name returned 
 | |
|   is a string of ASCII characters: the first character is bit8--bit15 
 | |
|   of the first word, the second character is bit0--bit7 of the first word 
 | |
|   and so on. Thus the string can not be print directly before it is 
 | |
|   preprocessed by this func to change the order of characters in 
 | |
|   each word in the string.
 | |
| 
 | |
|   @param[in] CHAR8 IN    *Destination
 | |
|   Indicates the destination string.
 | |
|   
 | |
|   @param[in] CHAR8 IN    *Source
 | |
|   Indicates the source string.
 | |
|   
 | |
|   @param[in] UINT8 IN    Size
 | |
|   the length of the string
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SwapStringChars (
 | |
|   IN CHAR8  *Destination,
 | |
|   IN CHAR8  *Source,
 | |
|   IN UINT32 Size
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   CHAR8   Temp;
 | |
| 
 | |
|   for (Index = 0; Index < Size; Index += 2) {
 | |
| 
 | |
|     Temp                    = Source[Index + 1];
 | |
|     Destination[Index + 1]  = Source[Index];
 | |
|     Destination[Index]      = Temp;
 | |
|   }
 | |
| }
 | |
| 
 | |
| //
 | |
| // ReleaseIdeResources
 | |
| //
 | |
| /**
 | |
|   Release resources of an IDE device before stopping it.
 | |
| 
 | |
|   @param[in] *IdeBlkIoDevice  Standard IDE device private data structure
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| ReleaseIdeResources (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice
 | |
|   )
 | |
| {
 | |
|   if (IdeBlkIoDevice == NULL) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Release all the resourses occupied by the IDE_BLK_IO_DEV
 | |
|   //
 | |
|   
 | |
|   if (IdeBlkIoDevice->SenseData != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->SenseData);
 | |
|     IdeBlkIoDevice->SenseData = NULL;
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->Cache != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->Cache);
 | |
|     IdeBlkIoDevice->Cache = NULL;
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->pIdData != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->pIdData);
 | |
|     IdeBlkIoDevice->pIdData = NULL;
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->pInquiryData != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->pInquiryData);
 | |
|     IdeBlkIoDevice->pInquiryData = NULL;
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->ControllerNameTable != NULL) {
 | |
|     FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
 | |
|     IdeBlkIoDevice->ControllerNameTable = NULL;
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->IoPort != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->IoPort);
 | |
|   }
 | |
| 
 | |
|   if (IdeBlkIoDevice->DevicePath != NULL) {
 | |
|     gBS->FreePool (IdeBlkIoDevice->DevicePath);
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (IdeBlkIoDevice);
 | |
|   IdeBlkIoDevice = NULL;
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| //
 | |
| // SetDeviceTransferMode
 | |
| //
 | |
| /**
 | |
|   Set the calculated Best transfer mode to a detected device
 | |
| 
 | |
|   @param[in] *IdeDev       Standard IDE device private data structure
 | |
|   @param[in] *TransferMode The device transfer mode to be set
 | |
| 
 | |
|   @return Set transfer mode Command execute status
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetDeviceTransferMode (
 | |
|   IN IDE_BLK_IO_DEV       *IdeDev,
 | |
|   IN ATA_TRANSFER_MODE    *TransferMode
 | |
|   )
 | |
| // TODO: function comment is missing 'Routine Description:'
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT8       DeviceSelect;
 | |
|   UINT8       SectorCount;
 | |
| 
 | |
|   DeviceSelect  = 0;
 | |
|   DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
 | |
|   SectorCount   = *((UINT8 *) TransferMode);
 | |
| 
 | |
|   //
 | |
|   // Send SET FEATURE command (sub command 0x03) to set pio mode.
 | |
|   //
 | |
|   Status = AtaNonDataCommandIn (
 | |
|             IdeDev,
 | |
|             SET_FEATURES_CMD,
 | |
|             DeviceSelect,
 | |
|             0x03,
 | |
|             SectorCount,
 | |
|             0,
 | |
|             0,
 | |
|             0
 | |
|             );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Send ATA command into device with NON_DATA protocol
 | |
| 
 | |
|   @param  IdeDev Standard IDE device private data structure
 | |
|   @param  AtaCommand The ATA command to be sent
 | |
|   @param  Device The value in Device register
 | |
|   @param  Feature The value in Feature register
 | |
|   @param  SectorCount The value in SectorCount register
 | |
|   @param  LbaLow The value in LBA_LOW register
 | |
|   @param  LbaMiddle The value in LBA_MIDDLE register
 | |
|   @param  LbaHigh The value in LBA_HIGH register
 | |
| 
 | |
|   @retval  EFI_SUCCESS Reading succeed
 | |
|   @retval  EFI_ABORTED Command failed
 | |
|   @retval  EFI_DEVICE_ERROR Device status error
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| AtaNonDataCommandIn (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINT8           AtaCommand,
 | |
|   IN  UINT8           Device,
 | |
|   IN  UINT8           Feature,
 | |
|   IN  UINT8           SectorCount,
 | |
|   IN  UINT8           LbaLow,
 | |
|   IN  UINT8           LbaMiddle,
 | |
|   IN  UINT8           LbaHigh
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT8       StatusRegister;
 | |
| 
 | |
|   Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((IdeDev->Device << 4) | 0xe0)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // ATA commands for ATA device must be issued when DRDY is set
 | |
|   //
 | |
|   Status = DRDYReady (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Pass parameter into device register block
 | |
|   //
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
 | |
| 
 | |
|   //
 | |
|   // Send command via Command Register
 | |
|   //
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
 | |
| 
 | |
|   //
 | |
|   // Wait for command completion
 | |
|   //
 | |
|   Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
|   if ((StatusRegister & ERR) == ERR) {
 | |
|     //
 | |
|     // Failed to execute command, abort operation
 | |
|     //
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Send ATA Ext command into device with NON_DATA protocol
 | |
| 
 | |
|   @param  IdeDev Standard IDE device private data structure
 | |
|   @param  AtaCommand The ATA command to be sent
 | |
|   @param  Device The value in Device register
 | |
|   @param  Feature The value in Feature register
 | |
|   @param  SectorCount The value in SectorCount register
 | |
|   @param  LbaAddress The LBA address in 48-bit mode
 | |
| 
 | |
|   @retval  EFI_SUCCESS Reading succeed
 | |
|   @retval  EFI_ABORTED Command failed
 | |
|   @retval  EFI_DEVICE_ERROR Device status error
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| AtaNonDataCommandInExt (
 | |
|   IN  IDE_BLK_IO_DEV  *IdeDev,
 | |
|   IN  UINT8           AtaCommand,
 | |
|   IN  UINT8           Device,
 | |
|   IN  UINT16          Feature,
 | |
|   IN  UINT16          SectorCount,
 | |
|   IN  EFI_LBA         LbaAddress
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT8       StatusRegister;
 | |
|   UINT8       SectorCount8;
 | |
|   UINT8       Feature8;
 | |
|   UINT8       LbaLow;
 | |
|   UINT8       LbaMid;
 | |
|   UINT8       LbaHigh;
 | |
| 
 | |
|   Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
 | |
|   //
 | |
|   IDEWritePortB (
 | |
|     IdeDev->PciIo,
 | |
|     IdeDev->IoPort->Head,
 | |
|     (UINT8) ((IdeDev->Device << 4) | 0xe0)
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // ATA commands for ATA device must be issued when DRDY is set
 | |
|   //
 | |
|   Status = DRDYReady (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Pass parameter into device register block
 | |
|   //
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
 | |
| 
 | |
|   //
 | |
|   // Fill the feature register, which is a two-byte FIFO. Need write twice.
 | |
|   //
 | |
|   Feature8 = (UINT8) (Feature >> 8);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
 | |
| 
 | |
|   Feature8 = (UINT8) Feature;
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
 | |
| 
 | |
|   //
 | |
|   // Fill the sector count register, which is a two-byte FIFO. Need write twice.
 | |
|   //
 | |
|   SectorCount8 = (UINT8) (SectorCount >> 8);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
 | |
| 
 | |
|   SectorCount8 = (UINT8) SectorCount;
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
 | |
| 
 | |
|   //
 | |
|   // Fill the start LBA registers, which are also two-byte FIFO
 | |
|   //
 | |
|   LbaLow  = (UINT8) RShiftU64 (LbaAddress, 24);
 | |
|   LbaMid  = (UINT8) RShiftU64 (LbaAddress, 32);
 | |
|   LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
 | |
| 
 | |
|   LbaLow  = (UINT8) LbaAddress;
 | |
|   LbaMid  = (UINT8) RShiftU64 (LbaAddress, 8);
 | |
|   LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
 | |
| 
 | |
|   //
 | |
|   // Send command via Command Register
 | |
|   //
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
 | |
| 
 | |
|   //
 | |
|   // Wait for command completion
 | |
|   //
 | |
|   Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
 | |
|   if ((StatusRegister & ERR) == ERR) {
 | |
|     //
 | |
|     // Failed to execute command, abort operation
 | |
|     //
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // SetDriveParameters
 | |
| //
 | |
| /**
 | |
|   Set drive parameters for devices not support PACKETS command
 | |
| 
 | |
|   @param[in] IdeDev       Standard IDE device private data structure
 | |
|   @param[in] DriveParameters The device parameters to be set into the disk
 | |
| 
 | |
|   @return SetParameters Command execute status
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetDriveParameters (
 | |
|   IN IDE_BLK_IO_DEV       *IdeDev,
 | |
|   IN ATA_DRIVE_PARMS      *DriveParameters
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT8       DeviceSelect;
 | |
| 
 | |
|   DeviceSelect  = 0;
 | |
|   DeviceSelect  = (UINT8) ((IdeDev->Device) << 4);
 | |
| 
 | |
|   //
 | |
|   // Send Init drive parameters
 | |
|   //
 | |
|   Status = AtaPioDataIn (
 | |
|             IdeDev,
 | |
|             NULL,
 | |
|             0,
 | |
|             INIT_DRIVE_PARAM_CMD,
 | |
|             (UINT8) (DeviceSelect + DriveParameters->Heads),
 | |
|             DriveParameters->Sector,
 | |
|             0,
 | |
|             0,
 | |
|             0
 | |
|             );
 | |
| 
 | |
|   //
 | |
|   // Send Set Multiple parameters
 | |
|   //
 | |
|   Status = AtaPioDataIn (
 | |
|             IdeDev,
 | |
|             NULL,
 | |
|             0,
 | |
|             SET_MULTIPLE_MODE_CMD,
 | |
|             DeviceSelect,
 | |
|             DriveParameters->MultipleSector,
 | |
|             0,
 | |
|             0,
 | |
|             0
 | |
|             );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   TODO: Add function description
 | |
| 
 | |
|   @param  IdeDev TODO: add argument description
 | |
| 
 | |
|   @retval  EFI_SUCCESS TODO: Add description for return value
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EnableInterrupt (
 | |
|   IN IDE_BLK_IO_DEV       *IdeDev
 | |
|   )
 | |
| {
 | |
|   UINT8 DeviceControl;
 | |
| 
 | |
|   //
 | |
|   // Enable interrupt for DMA operation
 | |
|   //
 | |
|   DeviceControl = 0;
 | |
|   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |