Пример #1
0
/**
  Enable Interrupt on IDE controller.

  @param  IdeDev   Standard IDE device private data structure

  @retval  EFI_SUCCESS Enable Interrupt successfully
**/
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;
}
Пример #2
0
/**
  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 IdeDev  pointer to IDE_BLK_IO_DEV data structure, used to record all the
                 information of the IDE device.

  @retval EFI_SUCCESS successfully detects device.

  @retval other       any failure during detection process will return this value.

**/
EFI_STATUS
DetectIDEController (
  IN  IDE_BLK_IO_DEV  *IdeDev
  )
{
  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 & ATA_STSREG_DRDY) == 0               &&
      (InitStatusReg & ATA_STSREG_DRDY) == 0           &&
      MasterDeviceType == SlaveDeviceType   &&
      SlaveDeviceType != ATAPI_DEVICE_TYPE) {
    SlaveDeviceExist = FALSE;
  }

  //
  // Indicate this channel has been detected
  //
  ChannelDeviceDetected = TRUE;
  return EFI_SUCCESS;
}
Пример #3
0
/**
  The is an event(generally the event is exitBootService event) call back function.
  Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.

  @param  Event   Pointer to this event
  @param  Context Event handler private data

**/
VOID
EFIAPI
ClearInterrupt (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  EFI_STATUS      Status;
  UINT64          IoPortForBmis;
  UINT8           RegisterValue;
  IDE_BLK_IO_DEV  *IdeDev;

  //
  // Get our context
  //
  IdeDev = (IDE_BLK_IO_DEV *) Context;

  //
  // Obtain IDE IO port registers' base addresses
  //
  Status = ReassignIdeResources (IdeDev);
  if (EFI_ERROR (Status)) {
    return;
  }

  //
  // Check whether interrupt is pending
  //

  //
  // Reset IDE device to force it de-assert interrupt pin
  // Note: this will reset all devices on this IDE channel
  //
  Status = AtaSoftReset (IdeDev);
  if (EFI_ERROR (Status)) {
    return;
  }

  //
  // Get base address of IDE Bus Master Status Regsiter
  //
  if (IdePrimary == IdeDev->Channel) {
    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
  } else {
    if (IdeSecondary == IdeDev->Channel) {
      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
    } else {
      return;
    }
  }
  //
  // Read BMIS register and clear ERROR and INTR bit
  //
  IdeDev->PciIo->Io.Read (
                      IdeDev->PciIo,
                      EfiPciIoWidthUint8,
                      EFI_PCI_IO_PASS_THROUGH_BAR,
                      IoPortForBmis,
                      1,
                      &RegisterValue
                      );

  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);

  IdeDev->PciIo->Io.Write (
                      IdeDev->PciIo,
                      EfiPciIoWidthUint8,
                      EFI_PCI_IO_PASS_THROUGH_BAR,
                      IoPortForBmis,
                      1,
                      &RegisterValue
                      );

  //
  // Select the other device on this channel to ensure this device to release the interrupt pin
  //
  if (IdeDev->Device == 0) {
    RegisterValue = (1 << 4) | 0xe0;
  } else {
    RegisterValue = (0 << 4) | 0xe0;
  }
  IDEWritePortB (
    IdeDev->PciIo,
    IdeDev->IoPort->Head,
    RegisterValue
    );

}