mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 12:54:17 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1965 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1965 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
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.             
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
    ide.c
 | 
						|
    
 | 
						|
Abstract: 
 | 
						|
    
 | 
						|
 | 
						|
Revision History
 | 
						|
--*/
 | 
						|
 | 
						|
#include "idebus.h"
 | 
						|
 | 
						|
BOOLEAN SlaveDeviceExist  = FALSE;
 | 
						|
BOOLEAN MasterDeviceExist = FALSE;
 | 
						|
 | 
						|
UINT8
 | 
						|
IDEReadPortB (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | 
						|
  IN  UINT16                Port
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  PciIo - TODO: add argument description
 | 
						|
  Port  - TODO: add argument description
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
IDEReadPortWMultiple (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | 
						|
  IN  UINT16                Port,
 | 
						|
  IN  UINTN                 Count,
 | 
						|
  IN  VOID                  *Buffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  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
 | 
						|
  
 | 
						|
 | 
						|
Arguments:
 | 
						|
  PciIo   - Pointer to the EFI_PCI_IO instance
 | 
						|
  Port    - IO port to read
 | 
						|
  Count   - No. of UINT16's to read
 | 
						|
  Buffer  - Pointer to the data buffer for read
 | 
						|
 | 
						|
++*/
 | 
						|
// TODO: function comment should end with '--*/'
 | 
						|
// TODO: function comment is missing 'Returns:'
 | 
						|
{
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
IDEWritePortB (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | 
						|
  IN  UINT16                Port,
 | 
						|
  IN  UINT8                 Data
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  PciIo - TODO: add argument description
 | 
						|
  Port  - TODO: add argument description
 | 
						|
  Data  - TODO: add argument description
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  // perform 1-byte data write to register
 | 
						|
  //
 | 
						|
  PciIo->Io.Write (
 | 
						|
              PciIo,
 | 
						|
              EfiPciIoWidthUint8,
 | 
						|
              EFI_PCI_IO_PASS_THROUGH_BAR,
 | 
						|
              (UINT64) Port,
 | 
						|
              1,
 | 
						|
              &Data
 | 
						|
              );
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
IDEWritePortW (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | 
						|
  IN  UINT16                Port,
 | 
						|
  IN  UINT16                Data
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  PciIo - TODO: add argument description
 | 
						|
  Port  - TODO: add argument description
 | 
						|
  Data  - TODO: add argument description
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  // perform 1-word data write to register
 | 
						|
  //
 | 
						|
  PciIo->Io.Write (
 | 
						|
              PciIo,
 | 
						|
              EfiPciIoWidthUint16,
 | 
						|
              EFI_PCI_IO_PASS_THROUGH_BAR,
 | 
						|
              (UINT64) Port,
 | 
						|
              1,
 | 
						|
              &Data
 | 
						|
              );
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
IDEWritePortWMultiple (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL   *PciIo,
 | 
						|
  IN  UINT16                Port,
 | 
						|
  IN  UINTN                 Count,
 | 
						|
  IN  VOID                  *Buffer
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  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
 | 
						|
  
 | 
						|
 | 
						|
Arguments:
 | 
						|
  PciIo   - Pointer to the EFI_PCI_IO instance
 | 
						|
  Port    - IO port to read
 | 
						|
  Count   - No. of UINT16's to read
 | 
						|
  Buffer  - Pointer to the data buffer for read
 | 
						|
 | 
						|
++*/
 | 
						|
// TODO: function comment should end with '--*/'
 | 
						|
// TODO: function comment is missing 'Returns:'
 | 
						|
{
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
BOOLEAN
 | 
						|
BadIdeDeviceCheck (
 | 
						|
  IN IDE_BLK_IO_DEV *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev  - TODO: add argument description
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  TODO: add return values
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  //
 | 
						|
  //  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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
GetIdeRegistersBaseAddr (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL         *PciIo,
 | 
						|
  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  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.
 | 
						|
                 ___________________________________________
 | 
						|
                |           | Command Block | Control Block |
 | 
						|
                |  Channel  |   Registers   |   Registers   |
 | 
						|
                |___________|_______________|_______________|
 | 
						|
                |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |
 | 
						|
                |___________|_______________|_______________|
 | 
						|
                | Secondary |  170h - 177h  |  376h - 377h  |
 | 
						|
                |___________|_______________|_______________|
 | 
						|
        
 | 
						|
                  Table 1. Compatibility resource mappings
 | 
						|
        
 | 
						|
     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.
 | 
						|
               ___________________________________________________
 | 
						|
              |           |   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
 | 
						|
        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.
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance
 | 
						|
  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to 
 | 
						|
                      receive IDE IO port registers' base addresses
 | 
						|
                      
 | 
						|
Returns:
 | 
						|
    
 | 
						|
--*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
ReassignIdeResources (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  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.
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
  IdeDev - The BLK_IO private data which specifies the IDE device
 | 
						|
  
 | 
						|
++*/
 | 
						|
// TODO: function comment should end with '--*/'
 | 
						|
// TODO: function comment is missing 'Returns:'
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
CheckPowerMode (
 | 
						|
  IDE_BLK_IO_DEV    *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 Routine Description:
 | 
						|
 
 | 
						|
  Read SATA registers to detect SATA disks
 | 
						|
 | 
						|
 Arguments:
 | 
						|
 | 
						|
  IdeDev - The BLK_IO private data which specifies the IDE device
 | 
						|
  
 | 
						|
++*/
 | 
						|
// TODO: function comment should end with '--*/'
 | 
						|
// TODO: function comment is missing 'Returns:'
 | 
						|
// 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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
DiscoverIdeDevice (
 | 
						|
  IN IDE_BLK_IO_DEV *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 Routine Description:
 | 
						|
 
 | 
						|
  Detect if there is disk connected to this port
 | 
						|
 | 
						|
 Arguments:
 | 
						|
 | 
						|
  IdeDev - The BLK_IO private data which specifies the IDE device
 | 
						|
  
 | 
						|
++*/
 | 
						|
// TODO: function comment should end with '--*/'
 | 
						|
// TODO: function comment is missing 'Returns:'
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DetectIDEController (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  
 | 
						|
  Name: DetectIDEController
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
      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.
 | 
						|
 
 | 
						|
            
 | 
						|
  Parameters:
 | 
						|
      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.
 | 
						|
 | 
						|
 | 
						|
  Returns:    
 | 
						|
      TRUE      
 | 
						|
            successfully detects device.
 | 
						|
 | 
						|
      FALSE
 | 
						|
            any failure during detection process will return this
 | 
						|
            value.
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
--*/
 | 
						|
// TODO: function comment is missing 'Routine Description:'
 | 
						|
// TODO: function comment is missing 'Arguments:'
 | 
						|
// TODO:    IdeDev - add argument and description to function comment
 | 
						|
// TODO:    EFI_SUCCESS - add return value to function comment
 | 
						|
// TODO:    EFI_NOT_FOUND - add return value to function comment
 | 
						|
{
 | 
						|
  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
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DRQClear (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:   DRQClear
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
            used to designate the timeout for the DRQ clear.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
            DRQ bit clear within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
            DRQ bit not clear within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Status Register will clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DRQClear2 (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:   DRQClear2
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ clear.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          DRQ bit clear within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          DRQ bit not clear within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Alternate Status Register will not clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DRQReady (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:   DRQReady
 | 
						|
 | 
						|
  
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
            used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
            DRQ bit set within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
            DRQ bit not set within the time out.
 | 
						|
            
 | 
						|
        EFI_ABORTED
 | 
						|
            DRQ bit not set caused by the command abort.
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Status Register will clear interrupt status.
 | 
						|
 | 
						|
--*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
DRQReady2 (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:   DRQReady2
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          DRQ bit set within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          DRQ bit not set within the time out. 
 | 
						|
        
 | 
						|
        EFI_ABORTED
 | 
						|
            DRQ bit not set caused by the command abort.
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Alternate Status Register will not clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
WaitForBSYClear (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:
 | 
						|
        WaitForBSYClear
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          BSY bit clear within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          BSY bit not clear within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Status Register will clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
WaitForBSYClear2 (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           TimeoutInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:
 | 
						|
        WaitForBSYClear2
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          BSY bit clear within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          BSY bit not clear within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Alternate Status Register will not clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
DRDYReady (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           DelayInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:
 | 
						|
        DRDYReady
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          DRDY bit set within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          DRDY bit not set within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Status Register will clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
DRDYReady2 (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeDev,
 | 
						|
  IN  UINTN           DelayInMilliSeconds
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:
 | 
						|
        DRDYReady2
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        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.
 | 
						|
 | 
						|
        UINTN     IN    TimeoutInMilliSeconds
 | 
						|
          used to designate the timeout for the DRQ ready.
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        EFI_SUCCESS
 | 
						|
          DRDY bit set within the time out.
 | 
						|
 | 
						|
        EFI_TIMEOUT
 | 
						|
          DRDY bit not set within the time out. 
 | 
						|
 | 
						|
 | 
						|
  Notes:
 | 
						|
        Read Alternate Status Register will clear interrupt status.
 | 
						|
--*/
 | 
						|
// 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
 | 
						|
//
 | 
						|
VOID
 | 
						|
SwapStringChars (
 | 
						|
  IN CHAR8  *Destination,
 | 
						|
  IN CHAR8  *Source,
 | 
						|
  IN UINT32 Size
 | 
						|
  )
 | 
						|
/*++
 | 
						|
  Name:
 | 
						|
        SwapStringChars
 | 
						|
 | 
						|
 | 
						|
  Purpose: 
 | 
						|
        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.
 | 
						|
 | 
						|
 | 
						|
  Parameters:
 | 
						|
        CHAR8 IN    *Destination
 | 
						|
          Indicates the destination string.
 | 
						|
 | 
						|
        CHAR8 IN    *Source
 | 
						|
          Indicates the source string.
 | 
						|
 | 
						|
        UINT8 IN    Size
 | 
						|
          the length of the string
 | 
						|
 | 
						|
 | 
						|
  Returns:  
 | 
						|
        none
 | 
						|
 | 
						|
  Notes:
 | 
						|
 | 
						|
--*/
 | 
						|
// TODO: function comment is missing 'Routine Description:'
 | 
						|
// TODO: function comment is missing 'Arguments:'
 | 
						|
// TODO:    Destination - add argument and description to function comment
 | 
						|
// TODO:    Source - add argument and description to function comment
 | 
						|
// TODO:    Size - add argument and description to function comment
 | 
						|
{
 | 
						|
  UINT32  Index;
 | 
						|
  CHAR8   Temp;
 | 
						|
 | 
						|
  for (Index = 0; Index < Size; Index += 2) {
 | 
						|
 | 
						|
    Temp                    = Source[Index + 1];
 | 
						|
    Destination[Index + 1]  = Source[Index];
 | 
						|
    Destination[Index]      = Temp;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// ReleaseIdeResources
 | 
						|
//
 | 
						|
VOID
 | 
						|
ReleaseIdeResources (
 | 
						|
  IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice
 | 
						|
  )
 | 
						|
/*++
 | 
						|
Routing Description:
 | 
						|
 | 
						|
  Release resources of an IDE device before stopping it.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeBlkIoDevice  --  Standard IDE device private data structure
 | 
						|
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
    NONE
 | 
						|
    
 | 
						|
---*/
 | 
						|
// TODO: function comment is missing 'Routine Description:'
 | 
						|
{
 | 
						|
  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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
SetDeviceTransferMode (
 | 
						|
  IN IDE_BLK_IO_DEV       *IdeDev,
 | 
						|
  IN ATA_TRANSFER_MODE    *TransferMode
 | 
						|
  )
 | 
						|
/*++
 | 
						|
Routing Description:
 | 
						|
 | 
						|
  Set the calculated Best transfer mode to a detected device
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev       --  Standard IDE device private data structure
 | 
						|
  TransferMode --  The device transfer mode to be set
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
    Set transfer mode Command execute status
 | 
						|
    
 | 
						|
---*/
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Send ATA command into device with NON_DATA protocol
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev      - Standard IDE device private data structure
 | 
						|
  AtaCommand  - The ATA command to be sent
 | 
						|
  Device      - The value in Device register
 | 
						|
  Feature     - The value in Feature register
 | 
						|
  SectorCount - The value in SectorCount register 
 | 
						|
  LbaLow      - The value in LBA_LOW register
 | 
						|
  LbaMiddle   - The value in LBA_MIDDLE register
 | 
						|
  LbaHigh     - The value in LBA_HIGH register
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS      - Reading succeed
 | 
						|
  EFI_ABORTED      - Command failed
 | 
						|
  EFI_DEVICE_ERROR - Device status error
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Send ATA Ext command into device with NON_DATA protocol
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev      - Standard IDE device private data structure
 | 
						|
  AtaCommand  - The ATA command to be sent
 | 
						|
  Device      - The value in Device register
 | 
						|
  Feature     - The value in Feature register
 | 
						|
  SectorCount - The value in SectorCount register 
 | 
						|
  LbaAddress - The LBA address in 48-bit mode
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS      - Reading succeed
 | 
						|
  EFI_ABORTED      - Command failed
 | 
						|
  EFI_DEVICE_ERROR - Device status error
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  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
 | 
						|
//
 | 
						|
EFI_STATUS
 | 
						|
SetDriveParameters (
 | 
						|
  IN IDE_BLK_IO_DEV       *IdeDev,
 | 
						|
  IN ATA_DRIVE_PARMS      *DriveParameters
 | 
						|
  )
 | 
						|
/*++
 | 
						|
Routine Description: 
 | 
						|
 | 
						|
  Set drive parameters for devices not support PACKETS command
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev       --  Standard IDE device private data structure
 | 
						|
  DriveParameters --  The device parameters to be set into the disk
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  SetParameters Command execute status
 | 
						|
    
 | 
						|
--*/
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EnableInterrupt (
 | 
						|
  IN IDE_BLK_IO_DEV       *IdeDev
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  TODO: Add function description
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  IdeDev  - TODO: add argument description
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS - TODO: Add description for return value
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT8 DeviceControl;
 | 
						|
 | 
						|
  //
 | 
						|
  // Enable interrupt for DMA operation
 | 
						|
  //
 | 
						|
  DeviceControl = 0;
 | 
						|
  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |