📄 ide.c
字号:
}
//
// 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) {
EfiLibFreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
IdeBlkIoDevice->ControllerNameTable = NULL;
}
if (IdeBlkIoDevice->IoPort != NULL) {
gBS->FreePool (IdeBlkIoDevice->IoPort);
}
if (IdeBlkIoDevice->DevicePath != NULL) {
gBS->FreePool (IdeBlkIoDevice->DevicePath);
}
if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
IdeBlkIoDevice->ExitBootServiceEvent = NULL;
}
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
// For ATA_SMART_CMD, we may need more timeout to let device
// adjust internal states.
//
if (AtaCommand == ATA_SMART_CMD) {
Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);
} else {
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 = AtaNonDataCommandIn (
IdeDev,
INIT_DRIVE_PARAM_CMD,
(UINT8) (DeviceSelect + DriveParameters->Heads),
0,
DriveParameters->Sector,
0,
0,
0
);
//
// Send Set Multiple parameters
//
Status = AtaNonDataCommandIn (
IdeDev,
SET_MULTIPLE_MODE_CMD,
DeviceSelect,
0,
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;
}
VOID
ClearInterrupt (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
Arguments:
Event - Pointer to this event
Context - Event hanlder private data
Returns:
--*/
{
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
//
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
);
return ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -