⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是EFI BIOS源代码中的与平台无关部分的代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//
// 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;
  
  //
  // 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.
  //
  if (ChannelDeviceDetected == FALSE) {
    Status = DetectIDEController (IdeDev);
    if (EFI_ERROR (Status)) {
      return EFI_NOT_FOUND;
    }
  }

  Status = EFI_NOT_FOUND;

  //
  // Device exists. test if it is an ATA device.
  // Prefer the result from DetectIDEController,
  // if failed, try another device type to handle
  // devices that not follow the spec.
  //
  if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
    if (MasterDeviceType == ATA_DEVICE_TYPE) {
      Status = ATAIdentify (IdeDev);
      if (EFI_ERROR (Status)) {
        Status = ATAPIIdentify (IdeDev);
        if (!EFI_ERROR (Status)) {
          MasterDeviceType = ATAPI_DEVICE_TYPE;
        }
      }
    } else {
      Status = ATAPIIdentify (IdeDev);
      if (EFI_ERROR (Status)) {
        Status = ATAIdentify (IdeDev);
        if (!EFI_ERROR (Status)) {
          MasterDeviceType = ATA_DEVICE_TYPE;
        }
      }
    }
  }
  if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
    if (SlaveDeviceType == ATA_DEVICE_TYPE) {
      Status = ATAIdentify (IdeDev);
      if (EFI_ERROR (Status)) {
        Status = ATAPIIdentify (IdeDev);
        if (!EFI_ERROR (Status)) {
          SlaveDeviceType = ATAPI_DEVICE_TYPE;
        }
      }
    } else {
      Status = ATAPIIdentify (IdeDev);
      if (EFI_ERROR (Status)) {
        Status = ATAIdentify (IdeDev);
        if (!EFI_ERROR (Status)) {
          SlaveDeviceType = ATA_DEVICE_TYPE;
        }
      }
    }
  }
  if (EFI_ERROR (Status)) {
    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
InitializeIDEChannelData (
  VOID
  )
/*++
  
  Name: InitializeIDEChannelData


  Purpose: 
      This function initializes all state data related to the detection of one
      channel.

  Parameters:


  Returns:
      EFI_SUCCESS

  Notes:
--*/
{
  ChannelDeviceDetected = FALSE;
  MasterDeviceExist = FALSE;
  MasterDeviceType  = 0xff;
  SlaveDeviceExist  = FALSE;
  SlaveDeviceType   = 0xff;
  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:
--*/
{
  EFI_STATUS  Status;
  UINT8       SectorCountReg;
  UINT8       LBALowReg;
  UINT8       LBAMidReg;
  UINT8       LBAHighReg;
  UINT8       InitStatusReg;
  UINT8       StatusReg;

  //
  // 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);
  if (EFI_ERROR (Status)) {
    DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
    return Status;
  }
  //
  // Read device signature
  //
  //
  // Select Master
  //
  IDEWritePortB (
    IdeDev->PciIo,
    IdeDev->IoPort->Head,
    (UINT8) ((0 << 4) | 0xe0)
    );
  gBS->Stall (100);
  SectorCountReg = IDEReadPortB (
                     IdeDev->PciIo,
                     IdeDev->IoPort->SectorCount
                     );
  LBALowReg      = IDEReadPortB (
                     IdeDev->PciIo,
                     IdeDev->IoPort->SectorNumber
                     );
  LBAMidReg      = IDEReadPortB (
                     IdeDev->PciIo,
                     IdeDev->IoPort->CylinderLsb
                     );
  LBAHighReg     = IDEReadPortB (
                     IdeDev->PciIo,
                     IdeDev->IoPort->CylinderMsb
                     );
  if ((SectorCountReg == 0x1) &&
      (LBALowReg      == 0x1) &&
      (LBAMidReg      == 0x0) &&
      (LBAHighReg     == 0x0)) {
    MasterDeviceExist = TRUE;
    MasterDeviceType  = ATA_DEVICE_TYPE;
  } else {
    if ((LBAMidReg      == 0x14) &&
        (LBAHighReg     == 0xeb)) {
      MasterDeviceExist = TRUE;
      MasterDeviceType  = ATAPI_DEVICE_TYPE;
    }
  }

  //
  // For some Hard Drive, it takes some time to get
  // the right signature when operating in single slave mode.
  // We stall 20ms to work around this.
  //
  if (!MasterDeviceExist) {
    gBS->Stall (20000);
  }

  //
  // Select Slave
  //
  IDEWritePortB (
    IdeDev->PciIo,
    IdeDev->IoPort->Head,
    (UINT8) ((1 << 4) | 0xe0)
    );
  gBS->Stall (100);
  SectorCountReg = IDEReadPortB (
                     IdeDev->PciIo,
                     IdeDev->IoPort->SectorCount
                     );
  LBALowReg  = IDEReadPortB (
                 IdeDev->PciIo,
                 IdeDev->IoPort->SectorNumber
                 );
  LBAMidReg  = IDEReadPortB (
                 IdeDev->PciIo,
                 IdeDev->IoPort->CylinderLsb
                 );
  LBAHighReg = IDEReadPortB (
                 IdeDev->PciIo,
                 IdeDev->IoPort->CylinderMsb
                 );
  StatusReg  = IDEReadPortB (
                 IdeDev->PciIo,
                 IdeDev->IoPort->Reg.Status
                 );
  if ((SectorCountReg == 0x1) &&
      (LBALowReg      == 0x1) &&
      (LBAMidReg      == 0x0) &&
      (LBAHighReg     == 0x0)) {
    SlaveDeviceExist = TRUE;
    SlaveDeviceType  = ATA_DEVICE_TYPE;
  } else {
    if ((LBAMidReg     == 0x14) &&
        (LBAHighReg    == 0xeb)) {
      SlaveDeviceExist = TRUE;
      SlaveDeviceType  = ATAPI_DEVICE_TYPE;
    }
  }

  //
  // When single master is plugged, slave device
  // will be wrongly detected. Here's the workaround
  // for ATA devices by detecting DRY bit in status
  // register.
  // NOTE: This workaround doesn't apply to ATAPI.
  //
  if (MasterDeviceExist && SlaveDeviceExist &&
      (StatusReg & DRDY) == 0               &&
      (InitStatusReg & DRDY) == 0           &&
      MasterDeviceType == SlaveDeviceType   &&
      SlaveDeviceType != ATAPI_DEVICE_TYPE) {
    SlaveDeviceExist = FALSE;
  }

  //
  // Indicate this channel has been detected
  //
  ChannelDeviceDetected = TRUE;
  return EFI_SUCCESS;
}

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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -